zoukankan      html  css  js  c++  java
  • 一类有趣的枚举问题

    四个嫌疑犯

    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

    有些时候,一些常用函数写的尽量简洁,会影响人的编程思维。比如上面问题中,如果把get_ans函数尽量简化,则能够少定义许多变量

    def a(*i):
        ret = list(map(lambda x: (ans >> ((x - 1) * 2)) & 3, i))
        return ret[0] if len(i) == 1 else ret
    
    
    def only_one(ans_list, my_ans):
        return len(ans_list) == 1 and ans_list[0] == my_ans
    
    
    def one():
        return True
    
    
    def two():
        return a(5) == (2, 3, 0, 1)[a(2)]
    
    
    def three():
        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 = a(3, 6, 2, 4)
        real_ans = [i for i in range(4) if diff_from_other(ans_group, i)]
        return only_one(real_ans, a(3))
    
    
    def four():
        same_group = ((1, 5), (2, 7), (1, 9,), (6, 10))
        real_ans = [i for i in range(4) if a(same_group[i][0]) == a(same_group[i][1])]
        return only_one(real_ans, a(4))
    
    
    def five():
        options = (8, 4, 9, 7)
        real_ans = [i for i in range(4) if a(options[i]) == a(5)]
        return only_one(real_ans, a(5))
    
    
    def six():
        group = ((2, 4,), (1, 6), (3, 10), (5, 9))
        real_ans = [i for i in range(len(group)) if a(group[i][0]) == a(8) and a(group[i][1]) == a(8)]
        return only_one(real_ans, a(6))
    
    
    def seven():
        cnt = [0] * 4
        for i in range(1, 11):
            cnt[a(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)[a(7)]
    
    
    def eight():
        options = (7, 5, 2, 10)
        real_ans = [i for i in range(4) if abs(a(options[i]) - a(1)) != 1]
        return only_one(real_ans, a(8))
    
    
    def nine():
        options = [6, 10, 2, 9]
        real_ans = [i for i in range(4) if (a(options[i]) == a(5)) != (a(1) == a(6))]
        return only_one(real_ans, a(9))
    
    
    def ten():
        cnt = [0] * 4
        for i in range(1, 11):
            cnt[a(i)] += 1
        real_ans = max(cnt) - min(cnt)
        return real_ans == (3, 2, 4, 1)[a(10)]
    
    
    def tos():
        s = []
        for i in range(1, 11):
            s.append("ABCD"[a(i)])
        return ''.join(s)
    
    
    def judge():
        return all(i() for i in (one, two, three, four, five, six, seven, eight, nine, ten))
    
    
    ans = 0
    for i in range(4 ** 10):
        ans = i
        if judge():
            print(tos())
    
    

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

  • 相关阅读:
    JsonResponse
    python导出数据到excel
    ftp上传文件到服务器
    js设计模式 —— 订阅发布模式
    reducer的作用
    redux设置和使用三大原则
    js事件监听
    图片占位符
    正则练习
    正则基础
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/8971771.html
Copyright © 2011-2022 走看看