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;
}