看程序员是如何做 “2018年刑侦科推理试题” 的

hello

各位小伙伴

最近过的怎么样

有没有按时吃饭,睡觉,敲代码

一定要照顾好自己呀~

看程序员是如何做 “2018年刑侦科推理试题” 的_第1张图片

不知道大家前段时间,有没有在朋友圈中收到一份,『2018的刑侦科目推理试题』娜娜偶然在朋友圈中看到过一次~

看程序员是如何做 “2018年刑侦科推理试题” 的_第2张图片

原图奉上,没有看过的小伙伴可以仔细的看一下哈~

看程序员是如何做 “2018年刑侦科推理试题” 的_第3张图片

我看到第一题的反应是

题呢?你到给我题呀~连题都不给我~我怎么知道答案~

看到第二题我的脑袋已经无法思考一片空白了~

这尼玛是什么玩意儿,简直就是一个坑啊,然后我就放弃了。

看程序员是如何做 “2018年刑侦科推理试题” 的_第4张图片

但是最近我看到各路大神对这道题进行了解答,我才意识到,原来看似这么不正经的题其实是有很正经的答案的~

娜娜~不禁想问,这的死多少脑细胞才能做出这样的推理题~看来我那900+多集的柯南是白看了~

python语言实现

看程序员是如何做 “2018年刑侦科推理试题” 的_第5张图片

#encoding: utf-8

# 《2018刑侦科推理试题》非穷举的 Python 解法

# 需要先安装约束解决库 `pip3 install python-constraint`

# 使用 Python 3.5 编写

from constraint import *

problem = Problem()

# a1 - a10 表示第一题到第十题的答案变量,答案使用“1”表示“A”, “2”表示“B”,以此类推

vars = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"]

problem.addVariables(vars, [1, 2, 3, 4])

#第 2 题

def a2_func(a2, a5):

return (a2 == 1 and a5 == 3) or (a2 == 2 and a5 == 4) or (a2 == 3 or a5 == 1) or (a2 == 4 or a5 == 2)

problem.addConstraint(a2_func, ["a2", "a5"])

#第 3 题

def a3_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

return (a3 == 1 and a6 == a2 == a4 != a3) or (a3 == 2 and a3 == a2 == a4 != a6) \

or (a3 == 3 and a3 == a6 == a4 != a2) or (a3 == 4 and a3 == a6 == a2 != a4)

problem.addConstraint(a3_func, vars)

#第 4 题

def a4_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

return (a4 == 1 and a1 == a5) or (a4 == 2 and a2 == a7) or (a4 == 3 and a1 == a9) or (a4 == 4 and a6 == a10)

problem.addConstraint(a4_func, vars)

#第 5 题

def a5_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

return (a5 == a8 == 1) or (a5 == a4 == 2) or (a5 == a9 == 3) or (a5 == a7 == 4)

problem.addConstraint(a5_func, vars)

#第 6 题

def a6_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

return (a6 == 1 and a2 == a4 == a8) or (a6 == 2 and a1 == a6 == a8) \

 or (a6 == 3 and a3 == a10 == a8) or (a6 == 4 and a5 == a9 == a8)

problem.addConstraint(a6_func, vars)

#第 7 题

def a7_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

all_answers = [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]

counter = [0, 0, 0, 0]

for a in all_answers: 

counter[a - 1] += 1

imin = counter.index(min(counter)) + 1

n = len(set(counter))

# 这题为“此10题种被选中的选项最少的为,ABCD选择,说明 ABCD 的数量个不相同”

return n == 4 and ((a7 == 1 and imin == 3) or (a7 == 2 and imin == 2) or (a7 == 3 and imin == 1) or (a7 == 4 and imin == 4))

problem.addConstraint(a7_func, vars)

#第 8 题

def a8_func(a8, a7, a5, a2, a10, a1):

adj = lambda x: abs(a1 - x) != 1

return (a8 == 1 and adj(a7)) or (a8 == 2 and adj(a5)) or (a8 == 3 and adj(a2)) or (a8 == 4 and adj(a10))

problem.addConstraint(a8_func, ["a8", "a7", "a5", "a2", "a10", "a1"])

#第 9 题

def a9_func(a1, a2, a5, a6, a9, a10):

cond1 = a1 == a6

cond = lambda x: cond1 != (x == a5)

return (a9 == 1 and cond(a6)) or (a9 == 2 and cond(a10)) or (a9 == 3 and cond(a2)) or (a9 == 4 and cond(a9))

problem.addConstraint(a9_func, ["a1", "a2", "a5", "a6", "a9", "a10"])

#第 10 题

def a10_func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):

all_answers = [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]

counter = [0, 0, 0, 0]

for a in all_answers: 

counter[a - 1] += 1

v = abs(max(counter) - min(counter))

return (a10 == 1 and v == 3) or (a10 == 2 and v == 2) or (a10 == 3 and v == 4) or (a10 == 4 and v == 1)

problem.addConstraint(a10_func, vars)

# 约束设置完毕,开始求解

solutions = problem.getSolutions()

print("可能的解决数量:{0}".format(len(solutions)))

chars = ['A', 'B', 'C', 'D']

for si in range(0, len(solutions)):

print("\n---------- 第 {0} 组结果 ----------".format(si + 1))

s = solutions[si]

for i in range(1, 11):

key = "a" + str(i)

answer = chars[s[key] - 1]

print("第 {0} 题答案:{1}".format(i, answer))

运行结果:

c++语言实现

看程序员是如何做 “2018年刑侦科推理试题” 的_第6张图片

C语言实现:

看程序员是如何做 “2018年刑侦科推理试题” 的_第7张图片

一上来就是两发,下面代码是精简后的代码。

#include

#define JUDGE(i, JA, JB, JC, JD) \

if (c[i] == 0 && (JA)) continue; \

if (c[i] == 1 && (JB)) continue; \

if (c[i] == 2 && (JC)) continue; \

if (c[i] == 3 && (JD)) continue; 

void main() {

int c[10], n[4], dn, sn, dc, sc; 

for (int k = 0; k < (1 << 20); ++k) {

n[0] = n[1] = n[2] = n[3] = 0;

for (int i = 0; i < 10; ++i) {

c[i] = ((k >> 2*i) & 3);

++n[c[i]];

}

dn = 0, sn = 10;

for (int i = 0; i < 4; ++i) {

if (dn < n[i]) {dn = n[i]; dc = i;}

if (sn > n[i]) {sn = n[i]; sc = i;}

}

JUDGE(1, c[4] != 2, c[4] != 3, c[4] != 0, c[4] != 1);

JUDGE(2, c[2] == c[5] || c[2] == c[1] || c[2] == c[3], 

c[5] == c[2] || c[5] == c[1] || c[5] == c[3],

c[1] == c[2] || c[1] == c[5] || c[1] == c[3], 

c[3] == c[2] || c[3] == c[1] || c[3] == c[5]);

JUDGE(3, c[0] != c[4], c[1] != c[6], c[0] != c[8], c[5] != c[9]);

JUDGE(4, c[4] != c[7], c[4] != c[3], c[4] != c[8], c[4] != c[6]);

JUDGE(5, c[7] != c[1] || c[7] != c[3], c[7] != c[0] || c[7] != c[5], 

c[7] != c[2] || c[7] != c[9], c[7] != c[4] || c[7] != c[8]);

JUDGE(6, sc != 2, sc != 1, sc != 0, sc != 3);

JUDGE(7, c[0] - c[6] == 1 || c[0] - c[6] == -1, 

c[0] - c[4] == 1 || c[0] - c[4] == -1, 

c[0] - c[1] == 1 || c[0] - c[1] == -1, 

c[0] - c[9] == 1 || c[0] - c[9] == -1);

if (c[0] == c[5]) {

JUDGE(8, c[4] == c[5], c[4] == c[9], c[4] == c[1], c[4] == c[8]);

} else {

JUDGE(8, c[4] != c[5], c[4] != c[9], c[4] != c[1], c[4] != c[8]);

}

JUDGE(9, dn - sn != 3, dn - sn != 2, dn - sn != 4, dn - sn != 1);

printf("1:%c, 2:%c, 3:%c, 4:%c, 5:%c, 6:%c, 7:%c, 8:%c, 9:%c, 10:%c",

'A'+c[0], 'A'+c[1], 'A'+c[2], 'A'+c[3], 'A'+c[4], 

'A'+c[5], 'A'+c[6], 'A'+c[7], 'A'+c[8], 'A'+c[9]);

}

}

Java语言实现

public static void answer(){

// 用 1234 分别对应 ABCD, 计算方便

int[] answers = {1,2,3,4};

// 群举答案

for (int q1 : answers) {

for (int q2 : answers) {

for (int q3 : answers) {

for (int q4 : answers) {

for (int q5 : answers) {

for (int q6 : answers) {

for (int q7 : answers) {

for (int q8 : answers) {

for (int q9 : answers) {

for (int q10 : answers) {

int[] questions = new int[10];

questions[0] = q1;

questions[1] = q2;

questions[2] = q3;

questions[3] = q4;

questions[4] = q5;

questions[5] = q6;

questions[6] = q7;

questions[7] = q8;

questions[8] = q9;

questions[9] = q10;

if (isEnd(questions)){

// 遍历输出符合条件的答案

for (int i = 0 ; i < 10; i++){

System.out.println((i+1) + ":" + questions[i]);

}

}

}

}

}

}

}

}

}

}

}

}

}

/**

* 判断每个答案是否符合题意

* 为了方便 questions 数组中从 0 开始,

* 题目比数组角标多 1(不要问为什么, 奏是这么开)

* 比如 question[0] 的值表示第 1 题答案

**/

static boolean isEnd(int[] questions){

// 第二题, 第 5 题的答案是

switch (questions[4]){

case 1:

// 如果第 5 题答案是 A, 判断第 2 题答案是不是 C 不是返回 false, 是继续

if(questions[1] != 3)

return false;

break;

case 2:

// 原理同上

if(questions[1] != 4)

return false;

break;

case 3:

// 原理同上

if(questions[1] != 1)

return false;

break;

case 4:

// 原理同上

if(questions[1] != 2)

return false;

break;

}

// 第 3 题, 以下选项中哪一题的答案与其他三项不同

switch (questions[2]){

case 1:

if(!(questions[2]!=questions[5] && questions[5]==questions[1] && questions[1] == questions[3]))

return false;

break;

case 2:

if(!(questions[5]!=questions[2] && questions[2]==questions[1] && questions[1] == questions[3]))

return false;

break;

case 3:

if(!(questions[1]!=questions[5] && questions[2]==questions[5] && questions[5] == questions[3]))

return false;

break;

case 4:

if(!(questions[3]!=questions[5] && questions[5]==questions[1] && questions[1] == questions[2]))

return false;

break;

}

// 第 4 题, 以下选项中那两题的答案相同

switch (questions[3]){

case 1:{

// 判断第 1 题与第 5 题答案是否相同

if (questions[0] != questions[4]){

return false;

}

break;

}

case 2:{

// 原理同上

if (questions[1] != questions[6]){

return false;

}

break;

}

case 3:{

// 原理同上

if (questions[0] != questions[8]){

return false;

}

break;

}

case 4:{

// 原理同上

if (questions[5] != questions[9]){

return false;

}

break;

}

}

// 第 5 题, 以下选项中哪一题的答案与本题相同

switch (questions[4]){

case 1:

// 判断第 8 题答案是否是 A

if (questions[7] != 1)

return false;

break;

case 2:

// 原理同上

if(questions[3] != 2)

return false;

break;

case 3:

// 原理同上

if (questions[8] != 3)

return false;

case 4:

// 原理同上

if (questions[6] != 4)

return false;

break;

}

// 第 6 题, 以下选项中哪两题的答案与第 8 题相同

switch (questions[5]){

case 1:

// 判断第 14 题答案是否与第 8 题答案相同

if(questions[1] != questions[7] || questions[4] != questions[7])

return false;

break;

case 2:

// 原理同上

if(questions[0] != questions[7] || questions[5] != questions[7])

return false;

break;

case 3:

// 原理同上

if(questions[2] != questions[7] || questions[9] != questions[7])

return false;

break;

case 4:

// 原理同上

if(questions[4] != questions[7] || questions[8] != questions[7])

return false;

break;

}

// 由于第 710 题问题是同类型的, 所以一块计算 start

int[] check10 = new int[5];

// 把每个题的答案 (1234) 作为新数组下表, value++ 计算出现次数

for (int i=0;i < questions.length;i++){

check10[questions[i]]++;

}

// 出现最少与最多选项的次数初始化为 A 的次数

int low = check10[1];

int longer = check10[1];

// 出现最少的选项, 初始化为 A

int lowA = 1;

// 最少与最多次数的选项相关计算

for (int i=1;i<5;i++) {

if(check10[i] >0 && check10[i] < low){

low = check10[i];

lowA = i;

}

if (check10[i] > longer){

longer = check10[i];

}

}

// 第 7 题, 在此十道题中, 被选中次数最少的选项字母为

switch (questions[6]){

case 1:

// 判断才出现最少的字母是否为 C

if (lowA != 3)

return false;

break;

case 2:

// 原理同上

if (lowA != 2)

return false;

break;

case 3:

// 原理同上

if (lowA != 1)

return false;

break;

case 4:

// 原理同上

if (lowA != 4)

return false;

break;

}

// 第 10 题, 在此 10 道题中, ABCD 四个字母出现次数最多与最少者的差为

// 最多次数与最少次数的差值

int t = longer-low;

switch (questions[9]){

case 1:

// 判断差值是否为 3

if (t != 3)

return false;

break;

case 2:

// 原理同上

if (t != 2)

return false;

break;

case 3:

// 原理同上

if (t != 4)

return false;

break;

case 4:

// 原理同上

if (t != 1)

return false;

break;

}

// 第 710 题校验 end

// 第 8 题, 以下选项中哪一题的答案与第 1 题的答案在字母中不相邻

switch (questions[7]) {

case 1:

// 判断第 7 题与第一题答案差值绝对是是否为 1

if (Math.abs(questions[6] - questions[0]) == 1)

return false;

break;

case 2:

// 原理同上

if (Math.abs(questions[4] - questions[0]) == 1)

return false;

break;

case 3:

// 原理同上

if (Math.abs(questions[1] - questions[0]) == 1)

return false;

break;

case 4:

// 原理同上

if (Math.abs(questions[9] - questions[0]) == 1)

return false;

break;

}

// 第 9 题, 已知第 1 题与第 6 题的答案相同与第 X 题与第 5 题的答案相同的真假性相反, 那么 X 为

// 判断第 1 题与第 6 题的答案是否相同

boolean isOne = questions[0]==questions[5]?true:false;

switch (questions[8]){

case 1:

if(isOne){

// 第 1 题与第 6 题相同, 第 6 题与第 5 题答案相同返回 false;

if (questions[5] == questions[4])

return false;

}else {

// 第 1 题与第 6 题不相同, 第 6 题与第 5 题答案不相同返回 false;

if (questions[5] != questions[4])

return false;

}

break;

case 2:

// 原理同上

if(isOne){

if (questions[9] == questions[4])

return false;

}else {

if (questions[9] != questions[4])

return false;

}

break;

case 3:

// 原理同上

if(isOne){

if (questions[1] == questions[4])

return false;

}else {

if (questions[1] != questions[4])

return false;

}

break;

case 4:

// 原理同上

if(isOne){

if (questions[8] == questions[4])

return false;

}else {

if (questions[8] != questions[4])

return false;

}

break;

}

return true;

}

public static void main(String[] args) {

answer();

}

看到上面的答案之后,娜娜躲在角落了瑟瑟发抖,大牛,不就是膝盖吗?我给还不行吗?

然后我看到了下面这条信息,这一是道杭州学军中学的推理社的招新题~招新题~

看程序员是如何做 “2018年刑侦科推理试题” 的_第8张图片

然后娜娜开始研究怎么把这道题解出来~

此时此刻娜娜

娜娜的心情就和外面的天气一样

当我以为这题没有答案的时候

有人做出了答案

当我以为做答案的都是大牛的时候

有人说这是入门级的题

当我想着别人能做我也能做到的时候

发现自己竟然做不出来

看程序员是如何做 “2018年刑侦科推理试题” 的_第9张图片

各位小伙伴

开往幼儿园的班车就要发车了

没做出来的小伙伴请上车

和娜娜一起回去学习

不要担心

我一定会回来的~~~

你可能感兴趣的:(看程序员是如何做 “2018年刑侦科推理试题” 的)