我正在尝试用C编写一个程序来解决以下cryptarithm:
一个 + 一个 = 两个
七是素数
九是一个完美的正方形
即,我需要找到一个,两个,七个和九个的数字值其中每个字母(o,n,e,t,w,s,v,i)都被赋予一个数值,而完整的数字也符合上述所有条件。
我正在考虑为每个单词创建一个int数组,然后1)检查每个单词是否符合条件(例如,是“七”的素数)然后2)检查每个单词是否在数组与其他单词的值一致,其他单词也可以满足各自的条件。
我无法真正看到这个工作,因为我必须在每次迭代中不断将int数组转换为单个int然后我不确定如何同时匹配数组中的每个元素与其他单词
也许知道每个单词必须为真的MIN和MAX数值范围会有用吗?
有什么想法吗?
答案 0 :(得分:5)
对于蛮力(ish)方法,我从素数seven
开始,并使用Sieve of Eratosthenes得到所有素数高达99999.你可以丢弃所有答案第2和第4位不一样。之后,您可以转到方格nine
,因为其中三个数字由素数seven
确定。这应该很好地缩小了可能性,然后你可以使用@pmg的答案来完成它: - )。
更新:以下C#程序似乎是这样做的
bool[] poss_for_seven = new bool[100000]; // this will hold the possibilities for `seven`
for (int seven = 0; seven < poss_for_seven.Length; seven++)
poss_for_seven[seven] = (seven > 9999); // `seven` must have 5 digits
// Sieve of Eratosthenes to make `seven` prime
for (int seven = 2; seven < poss_for_seven.Length; seven++) {
for (int j = 2 * seven; j < poss_for_seven.Length; j += seven) {
poss_for_seven[j] = false;
}
}
// look through the array poss_for_seven[], considering each possibility in turn
for (int seven = 10000; seven < poss_for_seven.Length; seven++) {
if (poss_for_seven[seven]) {
int second_digit = ((seven / 10) % 10);
int fourth_digit = ((seven / 1000) % 10);
if (second_digit == fourth_digit) {
int e = second_digit;
int n = (seven % 10); // NB: `n` can't be zero because otherwise `seven` wouldn't be prime
for (int i = 0; i < 10; i++) {
int nine = n * 1000 + i * 100 + n * 10 + e;
int poss_sqrt = (int)Math.Floor(Math.Sqrt(nine) + 0.1); // 0.1 in case of of rounding error
if (poss_sqrt * poss_sqrt == nine) {
int o = ((2 * e) % 10); // since 2 * `one` = `two`, we now know `o`
int one = o * 100 + n * 10 + e;
int two = 2 * one;
int t = ((two / 100) % 10);
int w = ((two / 10) % 10);
// turns out that `one`=236, `two`=472, `nine` = 3136.
// look for solutions where `s` != `v` with `s` and `v' different from `o`, `n`, `e`,`t`, `w` and `i`
int s = ((seven / 10000) % 10);
int v = ((seven / 100) % 10);
if (s != v && s != o && s != n && s != e && s != t && s != w && s != i && v != o && v != n && v != e && v != t && v != w && v != i) {
System.Diagnostics.Trace.WriteLine(seven + "," + nine + "," + one + "," + two);
}
}
}
}
}
}
似乎nine
始终等于3136,因此one
= 236且two
= 472.但是,seven
有21种可能性。如果添加约束,没有两个数字可以采用相同的值(这是上面的C#代码所做的),那么它只减少到一种可能性(虽然我的代码中的错误意味着这个答案最初有3种可能性):
seven,nine,one,two
56963,3136,236,472
答案 1 :(得分:3)
我刚刚找到时间来构建一个c程序来解决你的密码问题。 我认为在开始强力编程之前,在数学上解决问题将大大提高输出速度。
一些数学(数论): 由于ONE + ONE = TWO,因此不能超过4,因为ONE + ONE会产生4位数。也不能为0.两个以O结尾并且是偶数,因为它是2 * ONE。 将这3个滤波器应用于O,可能的值保持为O = {2,4} 因此,E可以是{1,2,6,7},因为(E + E)模数10必须= O.更具体地说,O = 2表示E = {1,6},O = 4表示E = {2, 7} 现在让我们过滤N.鉴于SEVEN是素数,N必须是奇数。 N也不能为5,因为以5结尾的所有内容都可被5整除。因此N = {1,3,7,9}
现在我们已经减少了对于大多数字符(O,E,N)的可能性,我们已经准备好用我们所有的残暴行为来打击这个密码,迭代次数大大减少。
继承C代码:
#include <stdio.h>
#include <math.h>
#define O 0
#define N 1
#define E 2
#define T 3
#define W 4
#define S 5
#define V 6
#define I 7
bool isPerfectSquare(int number);
bool isPrime(int number);
void printSolutions(int countSolutions);
int filterNoRepeat(int unfilteredCount);
int solutions[1000][8]; // solution holder
int possibilitiesO[2] = {2,4};
int possibilitiesN[4] = {1,3,7,9};
int possibilitiesE[4] = {1,6,2,7};
void main() {
int countSolutions = 0;
int numberOne;
// iterate to fill up the solutions array by: one + one = two
for(int o=0;o<2;o++) {
for(int n=0;n<4;n++) {
for(int e=2*o;e<2*o+2;e++) { // following code is iterated 2*4*2 = 16 times
numberOne = 100*possibilitiesO[o] + 10*possibilitiesN[n] + possibilitiesE[e];
int w = ((2*numberOne)/10)%10;
int t = ((2*numberOne)/100)%10;
// check if NINE is a perfect square
for(int i=0;i<=9;i++) { // i can be anything ----- 10 iterations
int numberNine = 1000*possibilitiesN[n] + 100*i + 10*possibilitiesN[n] + possibilitiesE[e];
if(isPerfectSquare(numberNine)) {
// check if SEVEN is prime
for(int s=1;s<=9;s++) { // s cant be 0 ------ 9 iterations
for(int v=0;v<=9;v++) { // v can be anything other than s ------- 10 iterations
if(v==s) continue;
int numberSeven = 10000*s + 1000*possibilitiesE[e] + 100*v + 10*possibilitiesE[e] + possibilitiesN[n];
if(isPrime(numberSeven)) { // store solution
solutions[countSolutions][O] = possibilitiesO[o];
solutions[countSolutions][N] = possibilitiesN[n];
solutions[countSolutions][E] = possibilitiesE[e];
solutions[countSolutions][T] = t;
solutions[countSolutions][W] = w;
solutions[countSolutions][S] = s;
solutions[countSolutions][V] = v;
solutions[countSolutions][I] = i;
countSolutions++;
}
}
}
}
}
}
}
}
// 16 * 9 * 10 * 10 = 14400 iterations in the WORST scenario, conditions introduced reduce MOST of these iterations to 1 if() line
// iterations consumed by isPrime() function are not taken in count in the aproximation above.
// filter solutions so that no two letter have the same digit
countSolutions = filterNoRepeat(countSolutions);
printSolutions(countSolutions); // voila!
}
bool isPerfectSquare(int number) { // check if given number is a perfect square
double root = sqrt((double)number);
if(root==floor(root)) return true;
else return false;
}
bool isPrime(int number) { // simple algoritm to determine if given number is prime, check interval from sqrt(number) to number/2 with a step of +2
int startValue = sqrt((double)number);
if(startValue%2==0) startValue--; // make it odd
for(int k=startValue;k<number/2;k+=2) {
if(number%k==0) return false;
}
return true;
}
void printSolutions(int countSolutions) {
for(int k=0;k<countSolutions;k++) {
int one = 100*solutions[k][O] + 10*solutions[k][N] + solutions[k][E];
int two = 100*solutions[k][T] + 10*solutions[k][W] + solutions[k][O];
int seven = 10000*solutions[k][S] + 1000*solutions[k][E] + 100*solutions[k][V] + 10*solutions[k][E] + solutions[k][N];
int nine = 1000*solutions[k][N] + 100*solutions[k][I] + 10*solutions[k][N] + solutions[k][E];
printf("ONE: %d, TWO: %d, SEVEN: %d, NINE %d\n",one,two,seven,nine);
}
}
int filterNoRepeat(int unfilteredCount) {
int nrSol = 0;
for(int k=0;k<unfilteredCount;k++) {
bool isValid = true;
for(int i=0;i<7;i++) { // if two letters match, solution is not valid
for(int j=i+1;j<8;j++) {
if(solutions[k][i]==solutions[k][j]) {
isValid = false;
break;
}
}
if(!isValid) break;
}
if(isValid) { // store solution
for(int i=0;i<8;i++) {
solutions[nrSol][i] = solutions[k][i];
}
nrSol++;
}
}
return nrSol;
}
如果您仍然对此感兴趣,可以亲自尝试代码:P。结果是一个单一的解决方案:ONE:236,TWO:472,SEVEN:56963,NINE:3136 这个解决方案与Stochastically的解决方案相同,确认了我认为的两种算法的正确性:)。 感谢您提供这个不错的密码并祝您度过愉快的一天!
答案 2 :(得分:2)
蛮力FTW!
#define ONE ((o*100) + (n*10) + e)
#define TWO ((t*100) + (w*10) + o)
#define SEVEN ((s*10000) + (e*1010) + (v*100) + n)
#define NINE ((n*1010) + (i*100) + e)
for (o = 1; o < 10; o++) { /* 1st digit cannot be zero (one) */
for (n = 1; n < 10; n++) { /* 1st digit cannot be zero (nine) */
if (n == o) continue;
for (e = 0; n < 10; n++) {
if (e == n) continue;
if (e == o) continue;
/* ... */
if (ONE + ONE == TWO) /* whatever */;
/* ... */
}
}
}