该问题出自《C语言名题精选百则技巧篇》
在一些游戏与休闲的书中,经常看到如下的字谜:
VINGT
CINQ
+ CINQ
TRENTE
写一个程序进行破解。
说明:
数字谜的规则是这样 的:
(1)不同的英文字母表示不同的数字,因此,题目中最左一行的TQE就是不同的数。
(2)每一个数最左边一位不是0,所以上面的谜题里,V、C、T都不是0.
(3)上面的题目是加,那就表示VINGT这个五位数与CINQ这个四位数的两倍相加后,会得到THRNTE这个六位数,并且数字的安排如谜语所示。
很多人会采用如下的形式
for (V=1;V<=9;V++)
for(I=0;I<=9;I++)
......
for(E=0;E<=9;E++){
VINGT = ....;
CINQ = ...;
THENTE = ...;
if(THENTE = VINGT+CINQ+CINQ){
......
}
}
这样做的耗时很长,我们可以先对这个谜进行分析来缩小字母所代表的数字的范围,范围越小,工作就越少,执行起来就越快。
(1)TRENTE 的最高位数T是(V+千进位)的进位,因为两位数相加,进位最大为1,T为0或者1,因为数字谜规则的(2)规定T不能为0,因此T=1
结论:T=1
(2)R为(V+千进位)所得两位数的个位数,千进位为三个数相加的进位,三个数相加的最大值为9+9+9=27,因此,最大进位为2,因此R的最大值为(V+2)%10,V最大为 9,因此,R最大值为(9+2)%10 = 1,R值为0或者1,因为T=1,因此R不能再等于1,R=0。
结论:R=0
(3)在(2)的基础上反推回去,(V+千进位)%10 = 0,V最大为9,千进位为1或者2,则推出V的值为8或者9.
结论:V=8或者9,也可以表示成8<=V<=9
(4)个位数相加(T+2*Q) = 个进位*10+E,T=1,2*Q为偶数,偶数和奇数的和为奇数,因此E为奇数,因为E不能为1,因此E为3,5,7,9
结论:E可能为3,5,7,9。
(5)十位数相加(G+2*N+个进位)=T+十进位*10,T=1,N不等于0,因此十进位不能等于0,十进位为1或者2。
百位数相加(N+2*I+十进位)=N+百进位*10,得出2*I+十进位 = 百进位*10,I不等于0,因此百进位不等于0,百进位为1或者2,百进位*10为偶数,2*I为偶数,因此十进 位为偶数,因此十进位为2
十进位为2,百进位为1或者2.
假设十进位为2,百进位为1------2*I+2 = 1*10,I=4
假设十进位为2,百进位为2------2*I+2 = 2*10,I=9
结论I = 4或者I=9
(6)千位数相加,(I+2*C+百进位) = E+千进位*10.
假设百进位为2,即I=9, 如果I=9, 又因为V为8或者9,V不等于I,因此,V=8. V=8,则千进位=2
因为E为3,5,7,9,E不等于I,E为3,5,7,E+千进位*10>=23
9+2*C+2>=23, 则C>=6,因为8和9已经被V和I占用了,因此C=6或者7.
假设C = 6,则E =3,看个位数相加(T+2*Q) = 个进位+E---->(1+2*Q) = 个进位*10+3.
如果个进位=1,则Q=6---->和C冲突,不成立;
如果个进位=2,则Q=11----->大于9不成立;
C=6,假设不成立;
假设C=7,则E = 5,看个位数相加(T+2*Q) = 个进位+E---->(1+2*Q) = 个进位*10+5.
如果个进位=1,则Q=7,---->和C冲突,不成立;
如果个进位=2,则Q=12>10,不成立;
假设百进位为2,即I=9的情况下,C的两个可能值都不成立,因此,百进位假设为2不成立,因此I不等于9,因此,I=4
结论:I=4.百进位为1.
(7)假设V =8,则千进位为2,因为百进位为1,看千位数相加(I+2*C+百进位)=千进位*10+E------>(4+2*C+1)=20+E>=23----->C>=9,则C=9
则E=3,看个位数相加(T+2*Q)=E+个进位*10----->(1+2*Q) = 3+个进位*10.;
假设个进位=2,(1+2*Q)>23 ,不成立,因此个进位为0或者1;
假设个进位=0,(1+2*Q)=3,Q=1,和T冲突,不成立,个进位为1;
1+2*Q = 13,---->Q=6;
个进位为1,看十位数相加(G+2*N+个进位)=十进位*10+T----->(G+2*N+1)=21------>G+2*N = 20,G为偶数,G<=8,N>=6;
8和9已经被V和C占据,假设N=6,则G=8和V冲突,不成立;
假设N=7,则G=6和Q=6冲突,不成立;
个进位为1的假设也不成立,----->E=3假设不成立----->C=9假设不成立----->V=8假设不成立 ;
结论V=9.千进位为1,E范围缩小为3,5,7.
(8) 看千位数相加(4+2*C+百进位)=千进位*10+E------>(4+2*C+1)=10+E;
假设E=3.则C=4,和I冲突,不成立;
假设E=5,则C=5,和E冲突,不成立;
假设E=7,则C=6无冲突,成立;
结论:E=7;C=6
(9)看个位数相加(1+2*Q) = E+个进位*10,---->(1+2*Q) = 7+个进位*10;个进位为0或者1
假设个进位为1,则Q=8;看十位数相加(G+2*N+1)= 21----->G+2*N=20.
现在可用的数只有2,3,5,8,G为偶数,
假设G为2,则N=9和V冲突不成立;
假设G为8,则N=6和C冲突,不成立;
假设个进位为1不成立,个进位为0
个进位为0,则Q=3
结论:Q=3
(10)现在可用的数只有2,5,8。看十位相加(G+2*N+个进位)=T+十进位*10----->(G+2*N+个进位) = 21---->G+2*N=21
很容易可以看出来,G=5,N=8.
总结,
V I N G T 9 4 8 5 1
C I N Q 6 4 8 3
+ C I N Q + 6 4 8 3
T R E N T E 1 0 7 8 1 7
我们可以在以上步骤的任意一个步骤开始编程,以下编程是在第(5)步结束的基础上开始编程。
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int V,I,N,G,T=1,C,Q,R=0,E;
long IN,VINGT,CINQ,TRENTE;
long sum;
printf("\nNumber Puzzle\n");
printf("\n VINGT");
printf("\n CINQ");
printf("\n+) CINQ");
printf("\n---------");
printf("\n TRENTE\n");
for(V=8;V<=9;V++)
for(I=4;I<=9;I=I+5)
if(I!=V&&I!=T)
for(N=2;N<=9;N++)
if(N!=I&&N!=V){
IN = 10*I+N;
for(G=2;G<=9;G++)
if(G!=N&&G!=I&&G!=V)
for(C=2;C<=9;C++)
if(C!=G&&C!=N&&C!=I&&C!=V)
for(Q=2;Q<=9;Q++)
if(Q!=C&&Q!=G&&Q!=N&&Q!=I&&Q!=V)
for(E=3;E<=9;E++)
if(E!=Q&&E!=C&&E!=N&&E!=I&&E!=Q){
TRENTE = ((((T*10+R)*10+E)*10+N)*10+T)*10+E;
VINGT = ((V*100+IN)*10+G)*10+T;
CINQ = (C*100+IN)*10+Q;
sum = VINGT+CINQ+CINQ;
if(sum == TRENTE){
printf("\n\nThe answer is:\n");
printf("\n%8ld",VINGT);
printf("\n%8ld",CINQ);
printf("\n+)%6ld",CINQ);
printf("\n--------");
printf("\n%8ld",TRENTE);
}
}
}
getchar();
return 0;
}
如果是在第(6)步基础上编程,可以将
for(I=4;I<=9;I=I+5)
if(I!=V&&I!=T)
注释掉,在
int V,I,N,G,T=1,C,Q,R=0,E;
改为
int V,I=4,N,G,T=1,C,Q,R=0,E;
在(7)(8)(9)基础上的编程不再赘述。
运行结果