运行要求
运行时间限制: 2sec
内存限制: 1024MB
原文链接
题目
从1号位到N号位有N个人。他们当中有只说真话的好人,还有说话真假不分的可疑人。i号位的人的发言中进行了Ai个陈述。i号位的人的第j号陈述由Xij和Yij构成。Yij为1的情况的话说明Xij是好人。Yij=0的情况的话,说明Xij是可疑的人。
这N个人中,好人最多有多少个?
输入前提条件
- 输入的数全部为整数
- 1<=N<=15
- 0<=Ai<=N-1
- 1<=Xij<=N
- Xij != i
- Xj1 != Xj2(j1 != j2)
- Yij = 0,1
- *
输入
输入都以以下标准从命令行输入
N
A1
X11 Y11
X12 Y12
.
.
X1A1 Y1A1
A2
X21 Y21
X22 Y22
X2A2 Y2A2
.
.
An
Xn1 Yn1
Xn2 Yn2
.
.
XnAn YnAn
输出
存在的好人的最大数
例1
输入
3
1
2 1
1
1 1
1
2 0
输出
2
1号位选手指出2号位选手是好人
2号位选手指出1号位选手是好人
3号位选手指出2号位选手是可疑人
->好人最多的情况,1号位选手和2号位选手是好人,3号位选手是可疑的人.这样的话可以在逻辑不矛盾的情况下达到最大好人牌的数量
例2
输入
3
2
2 1
3 0
2
3 1
1 0
2
1 1
2 0
输出
0
有一个玩家是好人的话,都会存在逻辑矛盾,所以不存在好人牌
例3
输入
2
1
2 0
1
1 0
输出
1
读懂题目
- 每一个人的发言都会说几号位玩家是好人,几号位玩家是坏人。
比如例2的输入
3 --> 有3位玩家
2 --> 1号位玩家2次发言
2 1 --> 1号位玩家说2号玩家是好人
3 0 --> 1号玩家说3号玩家是可疑人
2 --> 2号位玩家2次发言
3 1 --> 2号位玩家说3号玩家是好人
1 0 --> 2号位玩家说1号玩家是可疑的人
2 --> 2号位玩家2次发言
1 1 --> 2号位玩家说1号玩家是好人
2 0 --> 3号位玩家说2号玩家是可疑的人
我们可以把每个玩家的发言抽象成上面这样的图像。
解题思路
1.观察N,也就是玩家数。每个玩家要么是好人,要么是可以的人。那么所有的情况是2的N次方。N最大位15,那么2的15次方是32768。O(N)的复杂度的话是来得及的。
2.可以比特运算的方法,去遍历所有的情况,关于比特运算。我在另外一篇文章里,讲到过。AtCoder Context 128 C Swtich(控制开关)
3.每种情况下好人是固定的,可疑的人也是固定的
如上图,列出了3种情况,每种情况里,绿色的区域代表该位玩家是好人,红色区域代表该位玩家是可疑人
4.在好人和可疑的人都是固定的情况下,我们去寻找每个人的发言,看看每个人的发言存不存在和固定情况矛盾的地方
5.如何判断当前情况下的人的发言是不是存在矛盾的呢
6.可疑的人的发言有真话也有假话。好人的话都是真话,我们遍历好人的发言
7.把好人发言里指出的好人拿出来,放在一个容器里A(honest box)
8.把好人发言里的可疑人拿出来,放在一个容器里B(suspicious box)
9.如果给好人容器A里面与当前假设情况(current assumption)下的可疑人区域有重叠,那么这种假设不满足条件
10.如果可疑人容器B里面与当前假设情况(current assumption)的好人区域有重叠,那么这种假设不满足条件
11.把满足条件的情况摘出来,看哪种情况下好人牌最多
代码
N = int(input())
ARR = []
for i in range(N):
A = int(input())
X = []
Y = []
for j in range(A):
x, t = map(int, input().split())
if t == 1:
X.append(x)
else:
Y.append(x)
ARR.append([X,Y])
def calculate(n,arr):
result = []
for i in range(2**n):
cases = []
goods = set()
suspicious = set()
for j in range(n):
cases.append(i >> j & 1)
if i >> j & 1:
goods.add(j)
else:
suspicious.add(j)
res = judge(arr,cases,goods,suspicious)
if res:
result.append(len(goods))
if len(result) == 0:
print(0)
else:
print(max(result))
def judge(arr,cases,goods,suspicious):
tempGoods = set()
tempSuspicious = set()
if sum(cases) == 0:
return False
for index,ca in enumerate(cases):
if ca == 1:
for g in arr[index][0]:
tempGoods.add(g - 1)
for s in arr[index][1]:
tempSuspicious.add(s - 1)
if len(list(tempGoods & suspicious)) > 0:
return False
if len(list(tempSuspicious & goods)) > 0:
return False
return True
calculate(N,ARR)
总结
这道理考察了如何用比特运算的方法遍历,所有的情况
还有就是在某种假设情况下, 如何找出假设后衍射情况和假设情况的矛盾点
※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。