//译题
//★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\n",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\n", &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\n",count);
return 0;
}