一个名叫cao_julians的网友对《高质量》第三版第4.13节例4的实现提出了质疑,我认真核对后也觉得欠妥。问题主要是对TRUE的定义和理解。现在更新如下:
例4:协助破案。假设已经查清,有A、B、C、D、E五个嫌疑人可能参与制造了一起银行抢劫案,但是不知道其中到底哪几个人是真正的案犯。不过,有确凿证据表明:
① 如果A参与了作案,则B一定也会参与。
② B和C两人中只有一人参与了作案。
③ C和D要么都参与了作案,要么都没有参与。
④ D和E两个人中至少有一人参与作案。
⑤ 如果E作案,则A和D一定参与作案。
是不是有点绕口?我们可以用数理逻辑中的正规表达式来表示上述论断:
① A→B
② (B∧ C)∨( B∧C)
③ (C∧D)∨( C∧ D)
④ (D∨E)
⑤ E→(A∧D)
我们现在用1(可理解为TRUE)表示作案,0(可理解为FALSE)表示未作案,则每个人的取值范围就是{0,1}。然后我们在5个人取值的所有可能的组合空间中进行搜索,如果某个组合同时满足这5条线索,那么它就是本案的答案了。于是,上述正规表达式可以进一步表示为下列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来表示组合空间中某一个组合能够满足几条论断,如果出现了这样一个组合:它同时满足了这5条论断,那么它就是我们要找的组合。
程序见示例4-21。
示例4-21
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; // 计数器清0
count += ( A == 0 || ( A == 1 && B == 1 ) ) ? 1 : 0;
count += ( ( B + C ) == 1 ) ? 1 : 0;
count += ( C == D ) ? 1 : 0;
count += ( ( D + E ) >= 1 ) ? 1 : 0;
count += ( E == 0 ||
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");
return 0;
}
输出结果如下:
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.
上述方法有些舍近求远。实际上,这个问题的更好的解决办法是直接使用所有逻辑表达式的“与”的结果来判断,即定义count为逻辑变量并修改为hasFound,此法更直接了当。实现如下:
首先把逻辑表达式改为:
① !A || (A && B)
② (B && !C) || (!B && C)
③ (C && D) || (!C && !D)
④ D || E
⑤ !E || (E && A && D)
代码就可以如下修改为:
#include <stdio.h>
int main(void)
{
int A, B, C, D, E;
bool hasFound = false;
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++) {
hasFound = true;
hasFound = hasFound && (!A || (A && B));
hasFound = hasFound && ((B && !C) || (!B && C));
hasFound = hasFound && ((C && D) || (!C && !D));
hasFound = hasFound && (D || E);
hasFound = hasFound && (!E || (E && A && D));
if (hasFound) // 找到一个满足所有条件的组合
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");
return 0;
}
输出结果如下:
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.
感谢网友cao_julians的热心和支持!谢谢!