前言
遇到一些逻辑问题的时候,因为数据量不大的关系,我们通常只是需要人工枚举出所有的情况就可以。今天发现了怎么用计算机去枚举,况且记录一波。
逻辑枚举
问题 1:
警察局抓了a,b,c,d四名偷窃嫌疑犯,其中有一人是小偷。审问中:
a说:“我不是小偷”。
b说:“c是小偷”。
c说:“小偷肯定是d”。
d说:“c冤枉人”。
现在已经知道四人中三人说的是真话,一人说的是假话。问到底谁是小偷?
分析
问题只有4中情况,而且他们4个人说的话只有4句为真。假设小偷为x,他们四个人说的话可以转换为以下四条逻辑表达式:
- a的话:x !=a
- b的话:x = c
- c的话:x = d
- d的话:x != d
接下来就只需要枚举x可取的四个值,满足上面三条逻辑表达式有三条为真的情况就得到了正解
代码如下
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int x;
for (x = 'a'; x <= 'd'; x++)
if (((x != 'a') + (x == 'c') + (x == 'd') + (x !=' d')) == 3)
printf("%c",x);
return 0;
}
问题 2:
3位老师对某次数学竞赛进行预测,他们的预测为:
甲说: 学生A得第一名,学生B得第三名
乙说:学生C得第一名,学生D得第四名
丙说:学生D得第二名,学生A得第三名。
竞赛结果表明,他们都说对一半,说错一半,且无并列名次,试编写程序a,b,c,d各自的名称。
分析
如果不除去并列名次,则有
4
4
4^4
44种情况,人工枚举会稍显麻烦。我们还是可以按照上一题的思想进行枚举。
假设a,b,c,d分别表示学生A,学生B,学生C和学生D所获得的名次,那么三位教练说的话可以可以用如下逻辑表达式表示:
- 甲说的话:a = 1 , b = 3
- 乙说的话:c = 1 , d = 4
- 丙说的话:d = 2 , a = 3
由于他们说的话都只有一半是对的,所以我们可以得到以下条件句:
- (a=1) + (b=3) = 1
- (c=1) + (d=4) = 1
- (d=2) + (a=3) = 1
代码如下
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a,b,c,d;
for(a=1;a<=4;a++){
for(b=1;b<=4;b++)if(a!=b){//去除重复名次
for(c=1;c<=4;c++)if(a!=c&&b!=c){
d=10-a-b-c; //根据a,b,c的名次计算d的名次
if(a!=d&&b!=d&&c!=d){
if((a==1)+(b==3)==1&&(c==1)+(d==4)==1&&(d==2)+(a==3)==1)
printf("a=%d, b=%d, c=%d, d=%d",a,b,c,d);
}
}
}
}
return 0;
}
实战演练
问题描述
公安人员审问甲、乙、丙、丁四个嫌疑犯,已确知,这四个人当中仅有一人是偷窃者,还知道这四个人的答话,要么完全诚实,要么完全说谎。在回答公安人员的问话中:
甲说:“乙没有偷,是丁偷的。”
乙说:“我没有偷,是丙偷的。”
丙说:“甲没有偷,是乙偷的。”
丁说:“我没有偷,我用的那东西是我家里的。”
请根据上述四人答话,判断谁是偷窃者。
输入格式
无
输出格式
输出一个字符,表示偷窃者是谁,A表示甲,B表示乙,C表示丙,D表示丁。
分析
- 这对绝大多数人来说,都只是一道水题。虽然情况不少,我们只要通过人工的逻辑推理很快可以得到正确的答案。
- 下面我们继续用上面讲解到的思路进行求解,我们假设凶手为x,可以得到他们说的话对应的逻辑表示式:
- 甲说的话表示x != B , x = D
- 乙说的话表示x != B , x = C
- 丙说的话表示x != A , x = B
- 丁说的话表示x != D
- 因为甲乙丙说的话都包含两个部分,而且他们说的话要么全为真,要么全为假。(至于丁说的话对结果有没有影响,我还有点疑问)就可得以下条件句:
- (x!=‘B’)+(x=‘D’)!=1
- (x!=‘B’)+(x=‘C’)!=1
- (x!=‘A’)+(x=‘B’)!=1
代码如下
#include <iostream>
#include <cstdio>
#define x1 (x!='B')+(x=='D')
#define x2 (x!='B')+(x=='C')
#define x3 (x!='A')+(x=='B')
using namespace std;
int main()
{
int x;
for(x='A';x<='D';x++)
if((x1!=1)&&(x2!=1)&&(x3!=1))
printf("%c",x);
return 0;
}