您的位置:首页 > 编程语言 > C语言/C++

C语言每日一练——第74天:黑与白问题

2022-01-10 22:00 976 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: