USACO 1.3.4 Prime Cryptarithm

//译题
//★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;
}

 

posted @ 2013-08-02 00:00  Geekers  阅读(324)  评论(0编辑  收藏  举报