一、问题引入
小明在数学课上遇到一道奥数题是这样的,【】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求解
#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; }