C++案例——协助破案
题目
协助破案。假设已经查清,有 A、B、C、D、E 五个嫌疑人可能参与制造了一起抢劫银行案,但不知道其中哪几个是真正的案犯。不过,有确凿证据表明:
- 如果 A 参与了作案,则 B 一定也会参与。
- B 和 C 两人中只有一人参与了作案。
- C 和 D 要么都参与了作案,要么都没有参与。
- D 和 E 两个人中至少有一人参与作案。
- 如果 E 作案,则 A 和 D 一定参与作案。
分析
正规表达式
上述论断可以用数理逻辑中的正规表达式来表示:
- \(A \to B\)
- \(\left( {B \wedge \neg C} \right) \vee \left( {\neg B \wedge C} \right)\)
- \(\left( {C \wedge D} \right) \vee \left( {\neg C \wedge \neg D} \right)\)
- \(\left( {D \wedge E} \right) \vee \left( {\neg D \wedge E} \right) \vee \left( {D \wedge \neg E} \right)\)
- \(E \to \left( {A \wedge D} \right)\)
现在假设用 1(TRUE)表示作案,0(FALSE)表示未作案,则每个人的取值范围就是 \(\{0,1\}\) 。然后我们在 5 个人取值的所有可能的组合空间中进行搜索,同时满足这五条线索的一个组合就是本案的答案了。
C++ / C 逻辑表达式
于是上述正规表达式可以进一步表示为下列 C++ / C 逻辑表达式:
-
A==0 || (A==1 && B==1)
-
B+C == 1
-
C == D
-
D+E >= 1
-
E==0 || (E==1 && A==1 && D==1)
我们用另一个变量 count
来表示组合空间中某一个组合能够满足几条论断,如果出现了这样一个组合:它同时满足了这五条论断,那么它就是我们要找的组合。
实现
#include<stdio.h>
int main(void)
{
int A,B,C,D,E;
int count = 0;
for (A = 0; A < 2; A++)
{
for (B = 0; B < 2; B++)
{
for (C = 0; C < 2; C++)
{
for (D = 0; D < 2; D++)
{
for (E = 0; E < 2; E++)
{
count = 0; // 计数器清零
count += (A==0 || (A==1 && B==1));
count += (B+C == 1);
count += (C == D);
count += (D+E >= 1);
count += (E==0 || (E==1 && A==1 && D==1));
if (count == 5) // 找到一个满足所有条件的组合
{
goto finish;
}
}
}
}
}
}
finish:
printf("Suspect A is %s.\n", (A==1)?"a criminal":"not a criminal");
printf("Suspect B is %s.\n", (B==1)?"a criminal":"not a criminal");
printf("Suspect C is %s.\n", (C==1)?"a criminal":"not a criminal");
printf("Suspect D is %s.\n", (D==1)?"a criminal":"not a criminal");
printf("Suspect E is %s.\n", (E==1)?"a criminal":"not a criminal");
}
输出结果如下:
Suspect A is not a criminal.
Suspect B is not a criminal.
Suspect C is a criminal.
Suspect D is a criminal.
Suspect E is not a criminal.
摘自《高质量程序设计指南——C++/C语言 第3版》 P82
未经作者授权,禁止转载
THE END