前段时间江苏网警发布的“2018刑侦推理题”非常火,题目为:

没想到的是,本来是一套推理题,结果各路程序员大佬,主要是Python大神各显神通,运用Python内的 逻辑运算符 几乎不怎么费力地解决了这个问题。

我觉得有趣,便花了一些时间看了看大家的解法,把比较优雅的想法、代码组合起来放在了这里。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import time
options = [1, 2, 3, 4]


def rep(a):
    lll = {1: "A", 2: "B", 3: "C", 4: "D"}
    return lll[a]


def Q2(a2, a5):
    return{
        (3, 1): True,
        (4, 2): True,
        (1, 3): True,
        (2, 4): True,
    }.get((a5, a2), False)


def Q3(a, a3, a6, a2, a4):
    return{
        1: (a3 != a6) and (a3 != a2) and (a3 != a4),
        2: (a6 != a3) and (a6 != a2) and (a6 != a4),
        3: (a2 != a3) and (a2 != a6) and (a2 != a4),
        4: (a4 != a3) and (a4 != a6) and (a4 != a2),
    }.get(a)


def Q4(a, a1, a5, a2, a7, a9, a6, a10):
    return{
        1: a1 == a5,
        2: a2 == a7,
        3: a1 == a9,
        4: a6 == a10,
    }.get(a)


def Q5(a, a8, a4, a9, a7):
    return{
        1: a == a8,
        2: a == a4,
        3: a == a9,
        4: a == a7,
    }.get(a)


def Q6(a, a8, a2, a4, a1, a6, a3, a10, a5, a9):
    return{
        1: a8 == a2 and a8 == a4,
        2: a8 == a1 and a8 == a6,
        3: a8 == a3 and a8 == a10,
        4: a8 == a5 and a8 == a9,
    }.get(a)


def Q7min(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    stats = [0, 0, 0, 0]
    for i in [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]:
        stats[i - 1] += 1
    return options[stats.index(min(stats))]


def Q7(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    minA = Q7min(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
    return{
        1: minA == 3,
        2: minA == 2,
        3: minA == 1,
        4: minA == 4,
    }.get(a7)


def Q8(a8, a1, a7, a5, a2, a10):
    return{
        1: abs(a7 - a1) != 1,
        2: abs(a5 - a1) != 1,
        3: abs(a2 - a1) != 1,
        4: abs(a10 - a1) != 1,
    }.get(a8)


def Q9(a9, a6, a5, a10, a2, a1):
    return (a1 == a6) != {
        1: a6 == a5,
        2: a10 == a5,
        3: a2 == a5,
        4: a9 == a5,
    }.get(a9)


def calDiff(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    stats = [0, 0, 0, 0]
    for i in [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]:
        stats[i - 1] += 1
    return max(stats) - min(stats)


def Q10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    count = calDiff(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
    return{
        1: count == 3,
        2: count == 2,
        3: count == 4,
        4: count == 1,
    }.get(a10)


def check(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    # Processing form Q2 since Q1 is always right...
    if Q2(a2, a5) is False:
        return False
    if Q3(a3, a3, a6, a2, a4) is False:
        return False
    if Q4(a4, a1, a5, a2, a7, a9, a6, a10) is False:
        return False
    if Q5(a5, a8, a4, a9, a7) is False:
        return False
    if Q6(a6, a8, a2, a4, a1, a6, a3, a10, a5, a9) is False:
        return False
    if Q7(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) is False:
        return False
    if Q8(a8, a1, a7, a5, a2, a10) is False:
        return False
    if Q9(a9, a6, a5, a10, a2, a1) is False:
        return False
    if Q10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) is False:
        return False
    return True


time1 = time.time()
for a1 in options:
    for a2 in options:
        for a3 in options:
            for a4 in options:
                for a5 in options:
                    for a6 in options:
                        for a7 in options:
                            for a8 in options:
                                for a9 in options:
                                    for a10 in options:
                                        if check(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
                                            print('答案是:', rep(a1), rep(a2), rep(a3), rep(a4), rep(a5), rep(a6), rep(a7), rep(a8), rep(a9), rep(a10))
                                            break

time2 = time.time()

print('用时%s秒' % round(time2 - time1, 2))

这段代码最后通过Python – REPL 得到的结果是:

1
2
3
4
答案是: B C A C A C D A B A
用时1.63秒

***Repl Closed***

优点:

  1. 易读性。使用字典的get方法来表示了各个选项。
  2. 相对来讲,速度还可以。

参考了:

  1. 2018年刑侦推理试题解答 (用字典以及get函数表示选项)
  2. 2018年刑侦推理试题解答-python (较快地遍历答案)

更多资料:

  1. Python 代码性能优化技巧- IBM
  2. 逻辑运算符