C语言下解决谋杀案问题

问题的描述是这样的:日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。以下为4个嫌疑犯的供词。
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说。
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。

先有个简单思路:用0和1来表示ABCD四个人是否清白。则不妨设ABCD起初都为0,即都为清白的,再挨个假设其中一个说假话,则有:

  • 假设A说的是假话,则A=1 C=1 D=1 D=0,D产生矛盾。
  • 假设B说的是假话,则也有矛盾出现A=0 C=0 D=1 D=0。
  • 假设C说了假话,则A=0 C=1 D=0 D=0,C是凶手。
  • 假设D说了假话,有A=0 C=1 D=1 D=0,矛盾。
    可见C才是凶手,而且其他三种情况都出现了,D清白不清白的矛盾。故在代码中定义了一个D的对立面dd。

整段代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
int a, b, c, d = 0;
int dd = 0;
int main()
{
for (int i = 0; i &lt; 4; i++)
{
if (i == 1)
{
a = 1; c = 0; d = 1; dd = 0;
}
if (i == 2)
{
a = 0; c = 0; d = 1; dd = 0;
}
if (i == 3)
{
a = 0; c = 1; d = 0; dd = 0;
}
if (i == 4)
{
a = 0; c = 1; d = 1;
}
if (a + b + c + d + dd == 1 &amp;&amp; dd == d) //判断出正确的情况,加以区分和打印
{
printf("凶手是:\n");
if (a%2 == 1) printf("A\n");
if (b%2 == 1) printf("B\n");
if (c%2 == 1) printf("C\n");
if (d%2 == 1) printf("D\n");
}
}
}

网上也看到了其他方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
char killer;
for(killer='A'; killer&lt;='D'; killer++)//巧妙地利用ASCII 从A-D进行循环和比较
{
//下面分别对应每个人都供词 不是A 是C 是D 不是D
if (((killer!='A') + (killer=='C') + (killer=='D') + (killer!='D'))==3) //这里等于3表示 有三个人说了真话
{
printf("%c是凶手\n",killer);
break;
}
}
return 0;
}

也是在已推断出凶手是c的情况下,对几种不同假设进行了筛选,其中在利用for()循环语句中,利用ASCII从A-D进行比较是很巧妙的一个思路,可以借鉴。最后的筛选条件语句是:
if (((killer!='A') + (killer=='C') + (killer=='D') + (killer!='D'))==3)
对应上面分析的四种假设来说,当出现ABCD四个人三个说真话时,上式才会成立,也就会进行接下来的打印语句。其中可见if语句中的判断条件,分别对应四个人说的话,也就因此达到了判断凶手的目的。

反思:代码很巧妙,自己可以判断出凶手,但是转化成为代码实现功能,自己还很欠缺这方面的经验,逻辑很混乱,最后写出的代码也没有优化,复杂度相比之下一下子就高了上去。以后还是要注意加强这类经典问题方面的锻炼。