1089 狼人杀-简单版 (20 分)

1089 狼人杀-简单版 (20 分)

题意描述:

以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是狼人”,4 号玩家说:“5 号是好人”,5 号玩家说:“4 号是好人”。已知这 5 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?

本题是这个问题的升级版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?

输入格式:
输入在第一行中给出一个正整数 N(5≤N≤100)。随后 N 行,第 i 行给出第 i 号玩家说的话(1≤i≤N),即一个玩家编号,用正号表示好人,负号表示狼人。

输出格式:
如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A=a[1],…,a[M] 和 B=b[1],…,b[M],若存在 0≤k<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],则称序列 A 小于序列 B。若无解则输出 No Solution。

输入样例 1:

5
-2
+3
-4
+5
+4

输出样例 1:

1 4

输入样例 2:

6
+6
+3
+1
-5
-2
+4

输出样例 2(解不唯一):

1 5

输入样例 3:

5
-2
-3
-4
-5
-1

输出样例 3:

No Solution

解题思路:
Alice: (¦3」∠),没思路。
Bob:没思路,(¦3」∠)
Alice: 这种题算(・◇・)?神马,博弈论吗》》
Bob: 应该没这么高深吧,会不会是模拟题,就是逻辑稍微没那么明显。
Alice: 输出最小序列解,最小序列是blahblah,…最小序列不就是一般的遍历二维数组的顺序吗???
Bob: emm, 你这么一说,还真是的,就是一般遍历二维数组的顺序。
Alice: 有两个狼人,狼人中有且仅有一个人撒谎,一共有两人撒谎。这是不是就是逻辑啊,我们先假设出两个具体的狼人,然后去判断是不是 狼人中有且仅有一个人撒谎,一共有两人撒谎,如果是,就说明假设是成立的,如果不是就再看下一对,这样一直找下去,如果最后一对也找不到就是“No Solution”
Bob: w(°o°)w‼(•‘╻’•)꒳ᵒ꒳ᵎ(σ゚∀゚)σ…:*☆ 哎哟不错哦。我们可以记录下所有人说谎的次数和所有说谎人,然后判断说谎的次数是不是等于2并且说谎的人里面是不是只有一个狼人。
Alice: 只有两种谎言,一种是把狼人当成好人,一种是把好人当成狼人。
Bob: √√√√√√


代码:

  • Alice’s Python Version :
def main():
    N = int(input())
    # 接收输入的正整数 N
    data = []
    for x in range(N):
        data.append(int(input()))
    # 依次读入 N 位玩家的发言, N 个整数

    answer = "No Solution"
    # 先假定没有答案
    for x in range(N):
        for y in range(x + 1, N):
            # 从小序列到大序列依次尝试,就是从(1,2)(1,3)。。。(3,4)的顺序尝试
            if check(data, x, y):
                # 如果让 x, y 作为狼人是符合题意的
                answer = "{} {}".format(x + 1, y + 1)
                break
                # 马上 break 出去,不然可能会被较大序列的狼人对替代
        if answer != "No Solution":
            # 接着上面,马上break 出去
            break

    print(answer)
    # 输出答案


def check(data, x, y):
    # 判断 x, y 作为狼人是否可行
    lies = 0
    # N 位玩家中说谎的人的个数
    liers = []
    # N 位玩家中说谎的人
    wolfs = [x + 1, y + 1]
    # 事实,我们假设 x, y 是狼人,x, y为下标,加一才是大家所讲的编号。

    for index, _ in enumerate(data):
        # 依次检验众人的发言
        if data[index] < 0 and data[index] * -1 not in wolfs:
            # 把好人当成狼人,说谎
            lies += 1
            liers.extend([index])
            # 记录说谎的次数和说谎的人
        if data[index] > 0 and data[index] in wolfs:
            # 把狼人当成好人,说谎
            lies += 1
            liers.extend([index])
            # 记录说谎的次数和说谎的人

    if x in liers and y not in liers and lies == 2:
        # 狼人中有且只有一人说谎 且 共有两人说谎, 符合题意
        return True
    if x not in liers and y in liers and lies == 2:
        # 狼人中有且只有一人说谎 且 共有两人说谎,符合题意
        return True
    # 否则不符合题意
    return False


if __name__ == '__main__':
    main()


易错点:

  • 玩家的编号可能是两位数,这时,用字符串存储可能的狼人的ID就会出问题。如‘112’,既可以解释为1和12 也可以解释为11和2,还是用元组或者列表好,无歧义。
  • 有且仅有两人说谎,狼人有且仅有一人说谎。
  • 有两种谎言,一种是把狼人当成好人,一种是把好人当成狼人。

总结:
winner
For relax :


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值