//译题 //★Prime Cryptarithm 牛式 下面是一个乘法竖式,如果用我们给定的那几个数字来取代*,可以使式子成立的话,我们就叫这 个式子牛式. * * * x * * ------- * * * * * * ------- * * * * 数字只能取代*,当然第一位不能为0. 写一个程序找出所有的牛式. PROGRAM NAME: crypt1 INPUT FORMAT Line 1: 数字的个数. Line 2: N 个用空格分开的数字(每个数字都∈{1,2,3,4,5,6,7,8,9}) . SAMPLE INPUT (file crypt1.in) 5 2 3 4 6 8 OUTPUT FORMAT 共一行,一个数字.表示牛式的总数.下面是样例的那个牛式. 2 2 2 x 2 2 ------ 4 4 4 4 4 4 --------- 4 8 8 4 SAMPLE OUTPUT (file crypt1.out) 1
/* 这道题目也用枚举,由于数据比较小,所以可以全部遍历一遍, 再考虑0不能使用, 所以从111 开始到 999 ,11开始到99; 我写的代码有完全模拟竖式的味道, 用了5个数组分别存放牛式的每一行 2 2 2 t1[] x 2 2 t2[] ------ 4 4 4 t3[] 4 4 4 t4[] --------- 4 8 8 4 comp[] 实际上还有很多地方可以优化 S1 S4 S5 × S2 S3 约束条件只有3个:第3、4行是3位数,第5行是4位数。按S1到S5的顺序搜索。 如果S1×S2>10或者S1×S3>10,则3、4行肯定不是3位数,剪枝。 即S1*S2+S4*S2/10>=10 || S1*S3+S4*S3/10>=10 剪枝。 补充:从高位到低位,从小到大填数据,如果发现乘积超过999就剪枝。 */ --------------------------------------------------------------------------------------------------- 参考代码1(代码中附有解释) --------------------------------------------------------------------------------------------------- /* ID: china_l5 LANG:C TASK: crypt1 */ #include<stdio.h> int judge(int n, int *m, int s) //用来判断数 n 是否是数组 m 中的元素 { int i,*p = m ,flag; for(i=0;i<s;i++) { if(n==*p) {flag = 1; break;} else flag = 0; p++; } return flag; } char x[5], y[5]; int t1[5], t2[5],t3[5], t4[5], num[10], sum[5],comp[5]; // t1 竖式的第一行 t2 第二行 t3 第三行 t4 第四行 // num数组存放 可以用到的数 //comp 用于比较 int main() { freopen("crypt1.in","r",stdin); freopen("crypt1.out","w",stdout); int N,i,j,k,p,q,tmp,flag=0,count=0; scanf("%d",&N); //读入N for(i=0;i<N;i++) scanf("%d",&num[i]); //读入可以用到的数,存在num中 for(i=111;i<=999;i++) //遍历111 到 999 因为不能用 0 ,且牛式的第一行为一个三位数 { t1[3] = i/100; t1[2] = i%100/10; t1[1] = i%100%10; if(!judge(t1[3],num,N)) continue; //如果第一行中有不属于num数组中的数存在的话,continue if(!judge(t1[2],num,N)) continue; if(!judge(t1[1],num,N)) continue; for(j=11;j<=99;j++) //遍历 11到 99 理由同上 { flag=2; t2[2] = j/10; t2[1] = j%10; if(!judge(t2[2],num,N)) continue; //如果第二行中有不属于num数组中提供的数的话,continue if(judge(t2[1],num,N)) { for(q=1,tmp=0;q<=3;q++) //算出第三行的每个数 { t3[q] = ( t1[q] * t2[1] + tmp)%10 ; tmp = ( t1[q] * t2[1] + tmp)/10; } if (tmp>0) continue; //如果存在进位,continue,自己想想为什么 for(q=1,tmp=0;q<=3;q++) //算出第四行的每个数 { t4[q+1] = ( t1[q] * t2[2] + tmp)%10 ; tmp = ( t1[q] * t2[2] + tmp)/10; } //如果有进位的话,同上 if (tmp>0) continue; if(!judge(t3[1],num,N)) continue; //判断同上 if(!judge(t3[2],num,N)) continue; if(!judge(t3[3],num,N)) continue; if(!judge(t4[2],num,N)) continue; if(!judge(t4[3],num,N)) continue; if(!judge(t4[4],num,N)) continue; comp[1] = t3[1]; if(!judge(comp[1],num,N)) continue; comp[2] = (t3[2]+t4[2])%10; tmp=(t3[2]+t4[2])/10; if(!judge(comp[2],num,N)) continue; comp[3] = (t3[3]+t4[3]+tmp)%10; tmp=(t3[3]+t4[3]+tmp)/10; if(!judge(comp[3],num,N)) continue; comp[4] = t4[4]+tmp; if(!judge(comp[4],num,N)) continue; if(flag==2) count++; //count计数 } } } printf("%d ",count); //输出count return 0; } --------------------------------------------------------------------------------------------------- 参考代码2(这种算法的话,时间上反而多了点) --------------------------------------------------------------------------------------------------- #include<stdio.h> #include<string.h> int x,y,abc,de,f,g,h,count; char s[20],buf[100]; int main() { freopen("crypt1.in", "r", stdin); freopen("crypt1.out", "w", stdout); int i,ok; scanf("%d ", &i); fgets( s, 2*i, stdin); for(abc = 111; abc < 1000; abc++) for(de = 11; de < 100; de++) { f = abc * (de/10); g = abc * (de%10); h = abc * de; ok = 1; if( (f / 1000 > 0) || (g / 1000 > 0) || (h / 10000 > 0) )continue; sprintf(buf,"%d%d%d%d%d",abc,de,f,g,h); for(i = 0; i < strlen(buf); i++) if(strchr(s, buf[i]) == NULL) {ok = 0; break;} if(ok) count++; } printf("%d ",count); return 0; }