C语言-回溯例4
1,问题提出 日本数学家桥本吉彦教授于1993年10月在我国山东举行的中日美三国数学教育研讨会上向与会者提出以下填数趣题: 把1,2,...,9这9个数字填入下式的九个方格中(数字不得重复),使下面的分数等式成立
桥本教授当即给出了一个解答。这一分数式填数趣题究竟共有多少个解答? 试求出所有解答。(等式左边两个分数交换次序只算一个解答)。
2,回溯算法设计
设置a数组,式中每一□位置用一个数组元素来表示 .
为判断数字是否重复,设置中间变量g:若出现某两数字相同(即a(i)=a(k))或a(1)>a(4),则赋值g=0(重复标记)。
首先从a(1)=1开始,逐步给a(i)(1≤i≤9)赋值,每一个a(i)赋值从1开始递增至9。直至a(9)赋值,判断:
若i=9,g=1,等式同时满足,则为一组解,用n统计解的个数后,格式打印输出这组解。
若i<9 且g=1,表明还不到九个数字,则下一个a(i)从1开始赋值继续。
若a(9)=9 ,则返回前一个数组元素a(8)增1 赋值(此时,a(9)又从1开始)再试。若a(8)=9 ,则返回前一个数组元素a(7)增1 赋值再试。
依此类推,直到a(1)=9时,已无法返回,意味着已全部试毕,求解结束。
3,代码实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 int flag;//设置标志位 7 int k,i,sum,x,y,z; 8 int a[10]; 9 i=1; 10 a[i]=1;//附初始值 11 sum=0;//记录解得个数 12 while(1) 13 { 14 flag=1; 15 for(k=i-1;k>=1;k--) 16 { 17 if(a[k]==a[i]) 18 { 19 flag=0;//不满足条件,改变标志位 20 } 21 } 22 if(flag&&i==9)//得到一组解,输出 23 { 24 sum++; 25 x=a[2]*10+a[3]; 26 y=a[5]*10+a[6]; 27 z=a[8]*10+a[9]; 28 if((x*a[4]*a[7]+y*a[1]*a[7])==(z*a[1]*a[4])) 29 { 30 printf("first1:%d%d/%d+%d%d/%d=%d%d/%d\n",a[2],a[3],a[1],a[5],a[6],a[4],a[8],a[9],a[7]); 31 printf("first2:%d/%d+%d/%d=%d/%d",x,a[1],y,a[4],z,a[7]); 32 printf("\n"); 33 } 34 } 35 if(flag&&i<9) 36 { 37 i++; 38 a[i]=1; 39 continue; 40 } 41 while(a[i]==9&&i>1)i--;//回溯 42 if(a[i]==9&&i==1) 43 { 44 break; 45 } 46 else 47 { 48 a[i]++;//寻找下一条路径 49 } 50 } 51 printf("The sum is %d",sum); 52 return 0; 53 }
运行结果:
4,说明
上面代码实现的是题目要求的颠倒,即上面是两个空,下面是一个空,要实现题目要求,只需将将x,y,z改变一下即可。
另外如果左面的两个数次序颠倒算一次的话,只需在约束条件中增加一个条件即可:a[1]>a[4];