一类有趣的枚举问题

Posted weiyinfu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一类有趣的枚举问题相关的知识,希望对你有一定的参考价值。

四个嫌疑犯

ABCD4个嫌疑犯,A说是B干的,B说是D干的,C说不是我干的,D说B在说谎.
其中只有一人说的是真话( )是罪犯

4个人中只有一个人干了坏事,所以只有4种情况。对于答案1000,0100,0010,0001,只需要判断每个答案中有几个真话、几个假话,真话为1的那种情况就是答案。

10道刑侦科推理试题

技术分享图片

在这个问题中,最重要的信息是:单选题,如果忽略了这个条件,就会得到多个答案
10个问题,每个问题4中答案,总共有$4^10=2^20$种备选答案,验证每个答案是否自冾即可。

def get_ans_of(ans, i):
    return (ans >> ((i - 1) * 2)) & 3


def only_one(ans_list, my_ans):
    return len(ans_list) == 1 and ans_list[0] == my_ans


def one(ans):
    return True


def two(ans):
    five_ans = get_ans_of(ans, 5)
    second_ans = get_ans_of(ans, 2)
    return five_ans == (2, 3, 0, 1)[second_ans]


def three(ans):
    def diff_from_other(ans_list, i):
        for j in range(len(ans_list)):
            if j != i:
                if ans_list[i] == ans_list[j]:
                    return False
        return True

    ans_group = [get_ans_of(ans, i) for i in (3, 6, 2, 4)]
    real_ans = []
    for i in range(4):
        if diff_from_other(ans_group, i):
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 3))


def four(ans):
    same_group = ((1, 5), (2, 7), (1, 9,), (6, 10))
    real_ans = []
    for i in range(4):
        if get_ans_of(ans, same_group[i][0]) == get_ans_of(ans, same_group[i][1]):
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 4))


def five(ans):
    options = (8, 4, 9, 7)
    real_ans = []
    for i in range(4):
        if get_ans_of(ans, options[i]) == get_ans_of(ans, 5):
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 5))


def six(ans):
    group = ((2, 4,), (1, 6), (3, 10), (5, 9))
    real_ans = []
    for i in range(len(group)):
        x, y = group[i]
        x_ans = get_ans_of(ans, x)
        y_ans = get_ans_of(ans, y)
        if x_ans == get_ans_of(ans, 8) and y_ans == get_ans_of(ans, 8):
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 6))


def seven(ans):
    cnt = [0] * 4
    for i in range(1, 11):
        cnt[get_ans_of(ans, i)] += 1
    mi = 0
    for i in range(4):
        if cnt[i] < cnt[mi]:
            mi = i
    mi_count = 0
    for i in range(4):
        if cnt[i] == cnt[mi]:
            mi_count += 1
    if mi_count != 1:
        return False
    return mi == (2, 1, 0, 3)[get_ans_of(ans, 7)]


def eight(ans):
    options = (7, 5, 2, 10)
    real_ans = []
    for i in range(4):
        if abs(get_ans_of(ans, options[i]) - get_ans_of(ans, 1)) != 1:
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 8))


def nine(ans):
    one_six_same = get_ans_of(ans, 1) == get_ans_of(ans, 6)
    options = [6, 10, 2, 9]
    real_ans = []
    for i in range(4):
        x5_same = get_ans_of(ans, options[i]) == get_ans_of(ans, 5)
        if x5_same != one_six_same:
            real_ans.append(i)
    return only_one(real_ans, get_ans_of(ans, 9))


def ten(ans):
    cnt = [0] * 4
    for i in range(1, 11):
        cnt[get_ans_of(ans, i)] += 1
    real_ans = max(cnt) - min(cnt)
    return real_ans == (3, 2, 4, 1)[get_ans_of(ans, 10)]


def tos(ans):
    s = []
    for i in range(1, 11):
        s.append("ABCD"[get_ans_of(ans, i)])
    return ''.join(s)


def judge(ans):
    for i in (one, two, three, four, five, six, seven, eight, nine, ten):
        if not i(ans):
            return False
    return True


def main():
    for i in range(4 ** 10):
        if judge(i):
            print(tos(i))


if __name__ == '__main__':
    main()

答案是:BCACA CDABA

这类题目虽然可以用暴力枚举,但是人脑却能够规划出一条最佳推理路径,能够少考虑很多种情况,快速得到答案,这跟我喜欢玩的数独游戏、竖式字谜是一个道理。
如果能够破解人类思考问题时的启发式思想,那将是机器推理的一大步!

以上是关于一类有趣的枚举问题的主要内容,如果未能解决你的问题,请参考以下文章

python [代码片段]一些有趣的代码#sort

php 有趣的代码片段在某些时候可能会有用。

跟我一起实现一些有趣的多边形

带有红宝石集合/可枚举的酷技巧和富有表现力的片段[关闭]

执行代码时有时不显示对话框片段

超实用的php代码片段