Prime Cryptarithm

Prime Cryptarithm

Description

(这个命名不好的任务与质数无关,甚至实际上与质数无关。非常抱歉。)
Cryptarithm通常表示为一个纸笔的任务,其中解算器需要在算术术语或表达式的手动评估中用每个星号(或通常是字母)替换数字,以便用一致的应用数字的结果导出正确的表达。 一个典型的例子是这个cryptarithm,以其独特的解决方案显示:

    SEND            9567       S->9  E->5  N->6  D->7
  + MORE          + 1085       M->1  O->0  R->8
  -------        -------
   MONEY           10652       Y->2

以下是cryptarithm乘法问题,可以通过将指定的N个数字组中的数字替换为标有*的位置来解决。由于星号是通用的,因此输入的任何数字都可用于任何星号; 任何数字可以根据需要重复多次。
用密码集{2,3,5,7}考虑下面的cryptarithm:

      * * *
   x    * *
    -------
      * * *         <-- 部分乘积数1 -- 必须是三位数长
    * * *           <-- 部分乘积数2 -- 必须是三位数长
    -------
    * * * *

数字只能出现在标有“*”的地方。当然,不允许使用开头为0的非0数字。
部分乘积数必须是三位数长,即使一般情况可能有四位数的部分乘积数。
注意一下在美国的学校中教的“部分乘积”,第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积.

[Note that this diagram shows far more digits in its results than
the required diagram above which has three digit partial products!]

          a b c     <-- number 'abc'
        x   d e     <-- number 'de'; the 'x' means 'multiply'
     -----------
p1      * * * *     <-- product of e * abc; first star might be 0 (absent)
p2    * * * *       <-- product of d * abc; first star might be 0 (absent)
     -----------
      * * * * *     <-- sum of p1 and p2 (e*abc + 10*d*abc) == de*abc

PROGRAM NAME: crypt1

INPUT FORMAT

第一行:N,将被用到的数字的个数
第二行:N个空格分隔的用于解决cryptarithm问题的非零数字(每个数字都属于{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

OUTPUT DETAILS

这里解释为什么222x22是可以的:3位数乘2位数产生两个(相等!)部分乘积数,每个部分乘积数都是三个数字(根据需要)。答案有四位数字,使用的数字集合{2,4,8}中的每个数字都在提供的集合{2,3,4,6,8}中。
为什么222x23不行:

      2 2 2   <-- OK:  three digits, all members of {2, 3, 4, 6, 8}
        2 3   <-- OK:  two digits, all members of {2, 3, 4, 6, 8}
     ------
      6 6 6   <-- OK:  three digits, all members of {2, 3, 4, 6, 8}
    4 4 4     <-- OK:  three digits, all members of {2, 3, 4, 6, 8}
  ---------
    5 1 0 6   <-- NOT OK: four digits (good), but 5, 1, and 0 are not in
                                                    {2, 3, 4, 6, 8}

设计算法

这道题我起初遗漏了当然其实是英文没看懂,用例子运行程序得到4,把数字输出看之后发现另外三组328×88、423×82、436×88确实是满足其中大部分条件的,后面看到牛式觉得可能是位数有问题,原来不仅是数字要满足条件,位数也是要满足条件的,所以也把上面那句加粗了,引起一下注意。接下来说一下算法设计:
这道题其实挺简单的,读懂要求按照它的来就行了,一个三位数乘一个二位数,两个部分乘积数必须是三位数,那么结果也必须只能是四位数,基本条件就是这些了。那么就只用解决查找每个数是否在所提供的数集中,用求余的方法就行了,没什么难度。

C++编写

/*
ID: your_id_here
TASK: crypt1
LANG: C++                 
*/
#include<iostream>
using namespace std;

int N;
int digits[9];

bool check(int number,int size)
{
    int temp=0;
    while(size--)
    {
        bool flag=false;
        temp=number%10;
        number/=10;
        for(int i=0;i<N;++i)
        {
            if(temp==digits[i])
                flag=true;
        }
        if(!flag)
            return false;
    }
    return true;
}

void solve()
{
    int num,num2,rec=0;
    int pro1,pro2,pro3;
    for(int i=0;i<N;++i)
        for(int j=0;j<N;++j)
            for(int k=0;k<N;++k)
                for(int m=0;m<N;++m)
                    for(int n=0;n<N;++n)
                    {
                        num=digits[i]*100+digits[j]*10+digits[k];
                        num2=digits[m]*10+digits[n];
                        pro1=num*digits[n];
                        if(check(pro1,3) && pro1<1000)      //第一个部分乘积数不符合条件就直接考虑下一种情况
                        {
                            pro2=num*digits[m];
                            if(check(pro2,3) && pro2<1000)        //第二个部分乘积数不符合条件考虑下一种情况
                            {
                                pro3=pro2*10+pro1;
                                if(check(pro3,4) && pro3<10000)        //最终结果不符合条件考虑下一种情况
                                    ++rec;
                            }
                        }
                    }
    cout<<rec<<endl;
}

int main()
{
    freopen("crypt1.in","r",stdin);
    freopen("crypt1.out","w",stdout);
    cin>>N;
    for(int i=0;i<N;++i)
        cin>>digits[i];
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值