Skip to content

Commit e12fb71

Browse files
committed
add hunter.py
1 parent e3740cf commit e12fb71

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

hunter.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/local/bin/python3
2+
##########################################
3+
# 问题:
4+
# 有一条河,河边有一个猎人牵着一头狼,一个男人带着两个小男孩,还有一个女人带着两个小女孩
5+
# 如果猎人离开,狼就会把所有人吃掉
6+
# 如果男人离开,女人会把两个小男孩掐死
7+
# 如果女人离开,男人会把两个小女孩掐死
8+
# 河里有一条船,船上只能乘坐两人(狼算一人),只有猎人、男人、女人会划船
9+
# 如何使他们全部过河?
10+
11+
12+
##########################################
13+
# 思路:
14+
# 与农夫过河问题类似,参考 https://www.zhihu.com/question/29968331
15+
# 一共有 8 个人(包含狼),每个人有两个状态:分别为在河的一侧,以及在河的另一侧
16+
# 这两种状态可用一个二进制位表示,0 代表在河的一侧,1 代表在河的另一侧
17+
# 则可用一个 8 位二进制数表示这 8 个人的状态,进行组合,一共有 256 个状态
18+
# 通过坐船,可以使一种状态转变为另一种状态
19+
# 如果状态从 00000000 转换到 11111111, 则说明所有人均到达河的另一侧
20+
# 将两种可以相互转变的状态相互连接,可以构建出一个用于表示状态转移情况的图
21+
# 在图中找到一条从 00000000 到 11111111 的路径,即可解决该问题
22+
23+
24+
##########################################
25+
# 数据存储格式:
26+
# 使用 8 位二进制数进行表示,从高位到低位分别表示男人,男孩,男孩,女人,女孩,女孩,狼的状态
27+
28+
29+
# 船允许的所有状态,1 代表在船上
30+
# 将两个状态进行异或操作,发生变化的位就会置一,则说明置一的位所对应的人是在船上
31+
# 但是,船的行驶是有方向的,例如从 10000000 到 01000000 的状态是无法通过一次乘船达到的
32+
# 所以需要进行进一步判断,具体方法见下面的代码
33+
boatAllowedStates = [
34+
0b11000000, 0b10100000, 0b00011000, 0b00010100, 0b10000010,
35+
0b01000010, 0b00100010, 0b00010010, 0b00001010, 0b00000110,
36+
0b00000011, 0b10010000, 0b10000000, 0b00010000, 0b00000010
37+
]
38+
39+
# 以邻接矩阵的形式存储可能的状态转移情况
40+
# 矩阵的索引就是用于表示状态的 8 位二进制数(0~255)
41+
statesGraph = [([0] * 256) for i in range(256)] # 创建 256x256 二维数组
42+
43+
# 判断是否为危险的状态
44+
def is_dangerous(x):
45+
# 第一种不安全的情况:男人不在,女人在,男孩在
46+
if ( x & 0b10000000) == 0 and ( x & 0b00010000) != 0 and ( x & 0b01100000) != 0:
47+
return True
48+
if (~x & 0b10000000) == 0 and (~x & 0b00010000) != 0 and (~x & 0b01100000) != 0:
49+
return True
50+
# 第二种不安全的情况:女人不在,男人在,女孩在
51+
if ( x & 0b00010000) == 0 and ( x & 0b10000000) != 0 and ( x & 0b00001100) != 0:
52+
return True
53+
if (~x & 0b00010000) == 0 and (~x & 0b10000000) != 0 and (~x & 0b00001100) != 0:
54+
return True
55+
# 第三种不安全的情况:猎人不在,狼在,其他人在
56+
if ( x & 0b00000010) == 0 and ( x & 0b00000001) != 0 and ( x & 0b11111100) != 0:
57+
return True
58+
if (~x & 0b00000010) == 0 and (~x & 0b00000001) != 0 and (~x & 0b11111100) != 0:
59+
return True
60+
return False
61+
62+
# 构建该邻接矩阵
63+
for x in range(0, 256):
64+
if is_dangerous(x): # 判断 x 的状态是否危险
65+
continue
66+
for y in range(0, 256):
67+
if is_dangerous(y): # 判断 y 的状态是否危险
68+
continue
69+
# 如果通过坐船,可以使状态 x 转变为状态 y, 则使矩阵对应位置为 1
70+
tmp = x ^ y
71+
if tmp in boatAllowedStates:
72+
# 进一步判断,排除类似 10000000 到 01000000 的情况
73+
if tmp & x ^ tmp == 0 or tmp & x ^ tmp == tmp:
74+
statesGraph[x][y] = 1 # 连接图中能够能够转换的状态
75+
76+
# 通过图的深度优先搜索算法,找出一条从 0b00000000 到 0b11111111 的路径
77+
# ⚠️TODO:
78+
# 此时仅仅是找到了一条能够到达的路径,不一定是最佳的结果
79+
# 可考虑直接找出所有可行的结果
80+
# 或使用最短路径算法,找出乘船次数最少的结果
81+
visited = [0] * 256 # 用在图的深度优先搜索中,已访问的状态
82+
path = [257] * 256 # 用于存储路径,数组内元素为下一个状态, 257 代表尚未初始化
83+
84+
def dfs_with_path(src):
85+
visited[src] = 1
86+
for i in range(0, 256):
87+
if statesGraph[src][i] == 1 and visited[i] == 0 and visited[0b11111111] == 0:
88+
path[src] = i
89+
dfs_with_path(i)
90+
91+
dfs_with_path(0b00000000)
92+
93+
# 将路径显示在屏幕上
94+
tmp_path = 0
95+
while tmp_path != 0b11111111:
96+
print('{0:08b}'.format(tmp_path))
97+
tmp_path = path[tmp_path]
98+
if(tmp_path == 257):
99+
# 257 在本程序中代表未初始化的值,如果遇到 257,说明没找到这样的路径
100+
print("Not found!")
101+
exit()
102+
print('{0:08b}'.format(0b11111111))
103+
print("Found!")

0 commit comments

Comments
 (0)