一、问题引入

小明在数学课上遇到一道奥数题是这样的,【】3*6528=3【】*8256,在两个【】内填入相同的数字使得等式成立。

不用分析了,直接show代码:

    for(int i=1;i<=9;i++)
        if((i*10+3)*6528==(30+i)*8256)
            printf("%d",i);  //答案为4 

 

这就是最简单的枚举算法。

枚举算法的基本思想是:有序地去尝试每一种可能。

 

二、问题拓展

现在小明又遇到一个稍微复杂一点的奥数题,【】【】【】+【】【】【】=【】【】【】,将数字1~9分别填入9个【】中,每个数字智能使用一次使得等式成立。

分析:根据枚举思想我们只需要枚举每一位上所有可能的数就好了。

    int a,b,c,d,e,f,g,h,i,total=0;
    for(a=1;a<=9;a++)  //第1个数的百位
        for(b=1;b<=9;b++)  //第1个数的十位
            for(c=1;c<=9;c++)  //第1个数的个位
                for(d=1;d<=9;d++)  //第2个数的百位
                    for(e=1;e<=9;e++)  //第2个数的十位
                        for(f=1;f<=9;f++)  //第2个数的个位
                            for(g=1;g<=9;g++)  //第3个数的百位
                                for(h=1;h<=9;h++)  //第3个数的十位
                                    for(i=1;i<=9;i++)  //第3个数的个位 
    {  //接下来要判断每一位上的数互不相等 
        if(a!=b && a!=c && a!=d && a!=e && a!=f && a!=g && a!=h && a!=i
        && b!=c && b!=d && b!=e && b!=f && b!=g && b!=h && b!=i
        && c!=d && c!=e && c!=f && c!=g && c!=h && c!=i
        && d!=e && d!=f && d!=g && d!=h && d!=i
        && e!=f && e!=g && e!=h && e!=i
        && f!=g && f!=h && f!=i
        && g!=h && g!=i
        && h!=i
        && a*100+b*10+c+d*100+e*10+f==g*100+h*10+i)
        {
            total++;
            printf("%d%d%d+%d%d%d=%d%d%d\n",a,b,c,d,e,f,g,h,i);
        }
    }
    printf("total=%d",total/2);  //这是关键
    return 0; 

 

坑爹的奥数——枚举_算法

注意:因为173+286=459与286+173=459是同一种组合,因此我们在输出的时候需要将total的值除以2.

 

三、代码优化

但是上述代码中的if判断条件似乎太长了,我这辈子估计都很难看到如此冗杂的判断条件了...

所以我们用一个book数组来解决互不相等的问题:

    int a[10],i,total=0,book[10],sum;  //这里用a[1]-a[9]来代替刚才的a~i
    for(a[1]=1;a[1]<=9;a[1]++)
        for(a[2];a[2]<=9;a[2]++)
            for(a[3];a[3]<=9;a[3]++)
                for(a[4];a[4]<=9;a[4]++)
                    for(a[5];a[5]<=9;a[5]++)
                        for(a[6];a[6]<=9;a[6]++)
                            for(a[7];a[7]<=9;a[7]++)
                                for(a[8];a[8]<=9;a[8]++)
                                    for(a[9];a[9]<=9;a[9]++)
                                    {
                                        for(i=1;i<=9;i++)  //初始化数组
                                            book[i]=0;
                                        for(i=1;i<=9;i++)  //如果某个数出现过就标记一下
                                            book[a[i]]=1;
                                        sum=0;
                                        for(i=1;i<=9;i++)
                                            sum+=book[i];  //统计供出现了多少个不同的数 
                                        if(sum==9&&a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]==a[7]*100+a[8]*10+a[9])
                                        {
                                            total++;
                                            printf("%d%d%d+%d%d%d=%d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
                                        } 
                                    }
    printf("total=%d",total/2);
    return 0;

上面这段代码中,为了方便标记哪些数出现过,我将循环变量a、b、c、d、e、f、g、h、i用一个一维数组a代替,用book数组来标记1~9每个数是否出现过,默认为0,出现过的就设为1。然后我们只需要判断book数组中有多少个1就可以了。如果恰好有9个1则表示,1~9每个数都有且只出现过一次。

 

四、篇外:dfs求解

坑爹的奥数——枚举_算式求解_02坑爹的奥数——枚举_枚举_03
#include<stdio.h>
int a[10],book[10],total=0;
void dfs(int step)  //step表示现在站在第几个盒子面前
{
    int i;
    if(step==10)
    {
        if(a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]==a[7]*100+a[8]*10+a[9])
        {
            /*如果满足要求,可行解+1,并打印这个解*/ 
            total++;
            printf("%d%d%d+%d%d%d=%d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
        }
        return;  //返回之前的一步(最近调用的地方) 
    }
    /*站在第step个盒子面前,按照1、2、3...n的顺序一一尝试*/
    for(i=1;i<=9;i++)
    {
        if(book[i]==0)
        {
            a[step]=i;
            book[i]=1;
            dfs(step+1);
            book[i]=0;
        }
    } 
    return;
} 

int main()
{
    dfs(1);
    printf("total=%d",total/2);
    return 0;
}
奥数算式求解-dfs

 

    
版权声明:本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明。