C语言每日一练
2022年1月10日
文章目录
- 题目描述
- 问题分析
- 代码实现
- 运行结果
- 后期完善
- 网上参考
题目描述
有A、B、C、D、E这5个人,每个人额头上都帖了一张黑或白的纸。5人对坐,每个人都可以看到其他人额头上纸的颜色。5人相互观察后:
A说:“我看见有3人额头上贴的是白纸,1人额头上贴的是黑纸。”
B说:“我看见其他4人额头上贴的都是黑纸。”
C说:“我看见1人额头上贴的是白纸,其他3人额头上贴的是黑纸 。”
D说:“我看见4人额头上贴的都是白纸。”
E什么也没说。
现在己知额头上贴黑纸的人说的都是谎话,额头贴白纸的人说的都是实话。问这5人谁的额头上贴的是白纸,谁的额头上贴的是黑纸?
问题分析
个人思路:<仅供参考>
总共5个人,说话的只有4个,简单分析我们可以得知:
4个人说的情况都不相同。A说看到3个人贴白纸,B看到0张白纸,C看到1张白纸,D看到4张白纸,假设他们说的都是真话,那么他们4人所说的话对应的总白纸数依然不同(因为他们自己额头上贴的都是白纸,并不会使其中两人白纸总数相同)。
//4人贴白纸时,总白纸数#define A_TRUE (3 + 1) //其他3人贴白纸,自己也贴白纸#define B_TRUE (0 + 1)#define C_TRUE (1 + 1)#define D_TRUE (4 + 1)
所以我们可以得出一个隐藏条件——说话的4个人中只有1个人额头上贴白纸,即只有一个人说的是真话。
利用上面这个条件,我们可以通过所有人额头上的总白纸数来判断哪个人说的是真话,例如:B额头贴白纸,他说其他4人贴黑纸,在遍历所有情况时,如果总白纸数为1,且只有B贴白纸时,可能就是正确情况。
为什么说可能呢?由于每个人说的话中没有考虑自己头上的纸张颜色,所以可能会一种矛盾现象:
B额头上贴了白纸,他看到其他4人都贴的是黑纸,C虽然头上贴的的确是黑纸,但他的话是正确的:“我看见1人额头上贴的是白纸,其他3人额头上贴的是黑纸 ”。这就和题目条件冲突了——额头上贴黑纸的人说的都是谎话。
这样一来,在遍历时还需考虑当1个人贴白纸时,其他4个人都不能说真话这一条件,这一点依然可以通过总白纸数来判断。例如:当遍历到B说真话(额头贴白纸)时,判断5个人总白纸数是否等于A,C,D 3个人看到的白纸数(见下面的宏定义),如果有一个相等,说明该遍历结果是错误的。
//4人贴黑纸时,总白纸数(假设它们仍然说真话)#define A_FALSE (3) //自己贴黑纸,但说的是真话#define B_FALSE (0)#define C_FALSE (1)#define D_FALSE (4)
程序实现上,定义
a,b,c,d,e
5个变量,分别表示他们额头上贴的纸张颜色,1表示白色。通过5层
for
循环,遍历所以可能性,同时满足上面两种情况的,即为正确结果。
【注】我的思路可能推理得太深了,如果觉得处理得太麻烦,可以直接看下文网上参考的思路,该思路逻辑性更强,代码量更少。
代码实现
#include <stdio.h>//4人贴白纸时,总白纸数#define A_TRUE (3 + 1) //其他3人贴白纸,自己也贴白纸#define B_TRUE (0 + 1)#define C_TRUE (1 + 1)#define D_TRUE (4 + 1)//4人贴黑纸时,总白纸数(假设它们仍然说真话)#define A_FALSE (3) //自己贴黑纸,但说的是真话#define B_FALSE (0)#define C_FALSE (1)#define D_FALSE (4)int main(){int A = 0, B = 0, C = 0, D = 0, E = 0;int tmp = 0, flag = 0; //flag = 1表示找到正确结果for(A = 0; A <= 1; A++)for(B = 0; B <= 1; B++)for(C = 0; C <= 1; C++)for(D = 0; D <= 1; D++)for(E = 0; E <= 1; E++){//获取贴白纸的人数tmp = A + B + C + D + E;flag = 0;switch(tmp){//4人只有A贴白纸,且贴黑纸的人说的话不能为真case A_TRUE: if(A && !B && !C && !D &&tmp != B_FALSE &&tmp != C_FALSE &&tmp != D_FALSE)flag = 1;break;//4人只有B贴白纸,且贴黑纸的人说的话不能为真case B_TRUE: if(B && !A && !C && !D &&tmp != A_FALSE &&tmp != C_FALSE &&tmp != D_FALSE)flag = 1;break;//4人只有C贴白纸,且贴黑纸的人说的话不能为真case C_TRUE: if(C && !A && !B && !D &&tmp != A_FALSE &&tmp != B_FALSE &&tmp != D_FALSE)flag = 1;break;//4人只有D贴白纸,且贴黑纸的人说的话不能为真case D_TRUE: if(D && !A && !B && !C &&tmp != A_FALSE &&tmp != B_FALSE &&tmp != C_FALSE)flag = 1;break;}if(flag){printf("A贴%s\\n", A ? "白纸" : "黑纸");printf("B贴%s\\n", B ? "白纸" : "黑纸");printf("C贴%s\\n", C ? "白纸" : "黑纸");printf("D贴%s\\n", D ? "白纸" : "黑纸");printf("E贴%s\\n", E ? "白纸" : "黑纸");}}return 0;}
运行结果
后期完善
既然然已经推理出了A、B、C、D 4个人中只有一个人额头贴白纸,这时只需用一个
for
循环就能遍历出4个人中谁贴了白纸,循环次数为4次(0~3),分别表示A、B、C、D,这样可以减少一些无效的循环次数。
#include <stdio.h>//4人贴白纸时,总白纸数#define A_TRUE (3 + 1) //其他3人贴白纸,自己也贴白纸#define B_TRUE (0 + 1)#define C_TRUE (1 + 1)#define D_TRUE (4 + 1)//4人贴黑纸时,总白纸数(假设它们仍然说真话)#define A_FALSE (3) //自己贴黑纸,但说的是真话#define B_FALSE (0)#define C_FALSE (1)#define D_FALSE (4)int main(){//i表示A,B,C,D 4个人哪个贴白纸,j表示E是否贴白纸int i = 0, j = 0;int tmp = 0, flag = 0; //flag = 1表示找到正确结果for(i = 0; i < 4; i++)for(j = 0; j <= 1; j++){flag = 0;tmp = 1 + j; //总白纸数switch(i){//A说的是真话,其他人说假话?case 0: if(tmp == A_TRUE && tmp != B_FALSE &&tmp != C_FALSE && tmp != D_FALSE)flag = 1; break;//B说的是真话,其他人说假话?case 1: if(tmp == B_TRUE && tmp != A_FALSE &&tmp != C_FALSE && tmp != D_FALSE)flag = 1; break;//C说的是真话,其他人说假话?case 2: if(tmp == C_TRUE && tmp != A_FALSE &&tmp != B_FALSE && tmp != D_FALSE)flag = 1; break;//D说的是真话,其他人说假话?case 3: if(tmp == D_TRUE && tmp != A_FALSE &&tmp != B_FALSE && tmp != C_FALSE)flag = 1; break;}if(flag){printf("A贴%s\\n", i == 0 ? "白纸" : "黑纸");printf("B贴%s\\n", i == 1 ? "白纸" : "黑纸");printf("C贴%s\\n", i == 2 ? "白纸" : "黑纸");printf("D贴%s\\n", i == 3 ? "白纸" : "黑纸");printf("E贴%s\\n", j == 1 ? "白纸" : "黑纸");}}return 0;}
网上参考
原文链接:http://c.biancheng.net/cpp/html/3357.html
原文部分思路:
我的思路有一个很大的缺点,那就是花太多心思去推理了(推理过深),好处就是理解起来会好一点。这份代码通过逻辑表达式的方法,一个
if
语句就得出了结果,优点是逻辑性强,代码量少,不过理解起来可能需要一定的逻辑思维能力
#include<stdio.h>int main(){int a, b, c, d, e; /*0表示黑色,1表示白色*/for(a=0; a<=1; a++) /*穷举五个人额头帖纸颜色的全部可能*/for(b=0; b<=1; b++)for(c=0; c<=1; c++)for(d=0; d<=1; d++)for(e=0; e<=1; e++)if( (a&&b+c+d+e==3 || !a&&b+c+d+e!=3) &&(b&&a+c+d+e==0 || !b&&a+c+d+e!=0) &&(c&&a+b+d+e==1 || !c&&a+b+d+e!=1) &&(d&&a+b+c+e==4 || !d&&a+b+c+e!=4)){printf("A额头上的贴纸是%s色的.\\n",a?"白":"黑");printf("B额头上的贴纸是%s色的.\\n",b?"白":"黑");printf("C额头上的贴纸是%s色的.\\n",c?"白":"黑");printf("D额头上的贴纸是%s色的.\\n",d?"白":"黑");printf("E额头上的贴纸是%s色的.\\n",e?"白":"黑");}return 0;}