运行要求
运行时间限制: 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

读懂题目

  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号玩家是可疑的人

名称未設定.001.jpeg

我们可以把每个玩家的发言抽象成上面这样的图像。

解题思路
1.观察N,也就是玩家数。每个玩家要么是好人,要么是可以的人。那么所有的情况是2的N次方。N最大位15,那么2的15次方是32768。O(N)的复杂度的话是来得及的。

2.可以比特运算的方法,去遍历所有的情况,关于比特运算。我在另外一篇文章里,讲到过。AtCoder Context 128 C Swtich(控制开关)

名称未設定.002.jpeg

3.每种情况下好人是固定的,可疑的人也是固定的
如上图,列出了3种情况,每种情况里,绿色的区域代表该位玩家是好人,红色区域代表该位玩家是可疑人

4.在好人和可疑的人都是固定的情况下,我们去寻找每个人的发言,看看每个人的发言存不存在和固定情况矛盾的地方

5.如何判断当前情况下的人的发言是不是存在矛盾的呢

6.可疑的人的发言有真话也有假话。好人的话都是真话,我们遍历好人的发言

7.把好人发言里指出的好人拿出来,放在一个容器里A(honest box)

8.把好人发言里的可疑人拿出来,放在一个容器里B(suspicious box)

名称未設定.003.jpeg

名称未設定.004.jpeg

9.如果给好人容器A里面与当前假设情况(current assumption)下的可疑人区域有重叠,那么这种假设不满足条件

10.如果可疑人容器B里面与当前假设情况(current assumption)的好人区域有重叠,那么这种假设不满足条件

名称未設定.005.jpeg

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)

总结
这道理考察了如何用比特运算的方法遍历,所有的情况
还有就是在某种假设情况下, 如何找出假设后衍射情况和假设情况的矛盾点

※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
二维码.jpg



伟大不DIAO
1 声望1 粉丝

Done is better than perfect