囚犯问题
问题描述
囚犯问题是这样的:
一群囚犯将被带到牢房里坐牢。看守们把他们集中在一起,宣布:
- 每个囚犯将被单独关在一个牢笼里。
- 每天会随机的抽取一个囚犯放风。
- 放风的地方有一盏电灯,囚犯可以任意开关这盏灯。
- 电灯永远有电,永远不会损坏。
- 囚犯在放风的地方以及回来的路上都不会被其他囚犯看见。
- 牢房相互之间隔绝,囚犯相互之间不可能传递任何消息。
- 囚犯在放风时,除了开关电灯除了开关电灯不能留下任何痕迹或者信息。
- 看守只负责随机抽取囚犯,不会帮助囚犯传递信息。
- 如果有人确定所有人都放过风,则可以通知看守,看守确认之后可以把所有囚犯释放;如果永远没有人通知,或者通知的人弄错了(并不是所有人都被放风过),则所有人将永久坐牢,永无出头之日。
- 囚犯们可以商议一个方法出来以避免永久坐牢,商议好之后就会被关进各自的牢房。
问题:囚犯们会商议出什么方法?
概括
问题很长,但简单来说,就是在***一定范围内一直生成随机数,当范围内所有数都被生成一遍后停止并报告。***
这是一个简单的一进制问题,类似于我们掰手指头,有一个就伸出一根手指。直到所有手指全部伸出来。这个问题的点就是在于我们什么时候去伸出拿一根手指,即:我们如何知道有一个囚犯是第一次出来放风。突破点就在那盏电灯上。
解法
这个题应当这么解:
找一个人当计数员,在现实中可以随意找一个人,在计算机程序中为了方便,选取最后一个人作计数员。
如图,有没有多新的放过风的囚犯,计数员是以灯的开关为标准的,如果灯是开的就说明有人是第一次出来放风,放过风的人数就可以+1,直到所有普通囚犯计数完毕,再把自己加上,就是刚刚好。
现在,直接上代码:::::
import random
# n个囚犯,让随便一个做计数员
# 计数员见灯亮要关灯
# 普通囚犯第一次开灯,以后灭灯
def prison(n): # n个囚犯
counter = n - 1 # 计数员要知道一共有这么多人
switch = [False] * n # 所有人没开过灯
lamb = False # 灯一开始是关的
persons = 1 # 人数统计
while True:
num = random.randint(0, n - 1) # 随机拉一个囚犯
if num == n - 1: # 是计数员,如果灯开着,就关掉并+1,如果关着,就不管
if lamb:
persons += 1
lamb = False # 关灯
if persons == n: # 当计数等于所有人的时候
print('\n报告!所有人放风完毕')
break
else: # 人数不够继续
continue
else: # 灯是关着的不管
continue
else:
if lamb:
continue
else: # 如果灯是关着的
if switch[num]: # 如果该名囚犯开过灯,不开灯
continue
else: # 如果改名囚犯是第一次,打开灯
lamb = True
switch[num] = True
print('\n',num + 1, end='号囚犯开灯\n-------')
if __name__ == '__main__':
prison(100)
运行结果
"G:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\python.exe" E:/study/python/coding/PythonApplication1/PythonApplication1/囚犯问题.py
56号囚犯开灯
-------
57号囚犯开灯
-------
9号囚犯开灯
-------
83号囚犯开灯
-------
23号囚犯开灯
-------
93号囚犯开灯
-------
26号囚犯开灯
-------
36号囚犯开灯
-------
63号囚犯开灯
-------
37号囚犯开灯
-------
11号囚犯开灯
-------
39号囚犯开灯
-------
2号囚犯开灯
-------
43号囚犯开灯
-------
13号囚犯开灯
-------
55号囚犯开灯
-------
27号囚犯开灯
-------
70号囚犯开灯
-------
79号囚犯开灯
-------
89号囚犯开灯
-------
85号囚犯开灯
-------
8号囚犯开灯
-------
34号囚犯开灯
-------
28号囚犯开灯
-------
46号囚犯开灯
-------
7号囚犯开灯
-------
62号囚犯开灯
-------
80号囚犯开灯
-------
14号囚犯开灯
-------
21号囚犯开灯
-------
53号囚犯开灯
-------
68号囚犯开灯
-------
58号囚犯开灯
-------
61号囚犯开灯
-------
54号囚犯开灯
-------
48号囚犯开灯
-------
17号囚犯开灯
-------
35号囚犯开灯
-------
59号囚犯开灯
-------
67号囚犯开灯
-------
91号囚犯开灯
-------
24号囚犯开灯
-------
38号囚犯开灯
-------
20号囚犯开灯
-------
66号囚犯开灯
-------
77号囚犯开灯
-------
6号囚犯开灯
-------
65号囚犯开灯
-------
60号囚犯开灯
-------
12号囚犯开灯
-------
47号囚犯开灯
-------
98号囚犯开灯
-------
1号囚犯开灯
-------
69号囚犯开灯
-------
78号囚犯开灯
-------
92号囚犯开灯
-------
84号囚犯开灯
-------
72号囚犯开灯
-------
31号囚犯开灯
-------
71号囚犯开灯
-------
64号囚犯开灯
-------
16号囚犯开灯
-------
4号囚犯开灯
-------
73号囚犯开灯
-------
87号囚犯开灯
-------
96号囚犯开灯
-------
42号囚犯开灯
-------
40号囚犯开灯
-------
82号囚犯开灯
-------
19号囚犯开灯
-------
90号囚犯开灯
-------
41号囚犯开灯
-------
22号囚犯开灯
-------
5号囚犯开灯
-------
10号囚犯开灯
-------
44号囚犯开灯
-------
30号囚犯开灯
-------
95号囚犯开灯
-------
97号囚犯开灯
-------
33号囚犯开灯
-------
81号囚犯开灯
-------
75号囚犯开灯
-------
52号囚犯开灯
-------
99号囚犯开灯
-------
86号囚犯开灯
-------
45号囚犯开灯
-------
88号囚犯开灯
-------
18号囚犯开灯
-------
3号囚犯开灯
-------
49号囚犯开灯
-------
29号囚犯开灯
-------
25号囚犯开灯
-------
76号囚犯开灯
-------
15号囚犯开灯
-------
94号囚犯开灯
-------
51号囚犯开灯
-------
74号囚犯开灯
-------
32号囚犯开灯
-------
50号囚犯开灯
-------
报告!所有人放风完毕
进程已结束,退出代码为 0