约瑟夫问题
据说著名犹太历史学家 Josephus有过以下的故事:
在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想死,那么约瑟夫及其朋友应该怎样安排自己得位置才能逃过一劫?
算法
- 有n个人围成一圈,顺序排号。
- 从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,重新计数。
- 循环直到剩下最后N个人
代码
n = int(input("输入N: ")) # 输入总人数
ll = [i + 1 for i in range(n)] # 生成队列
print(ll)
suvivor = 2 # 设定最后得幸存者
i = 0
l = len(ll)
k = 1 # 报数
while l > suvivor:
if i == len(ll): # 报数结束,从第一个人重新开始报数
i = 0
if k == 3: # 0. 报数到 3:
print("kill : ", ll[i])
ll.pop(i) # 1. 移除这个人
l = len(ll) # 2. 新的队列长度
k = 1 # 3. 报数回归到1
i -= 1 # 4. 因为删掉一个人,所以当前坐标 -1,否则后面坐标加上以后,就会出错。
else:
k += 1
i += 1
print(ll)
结果
输入N: 41
[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]
kill : 3
kill : 6
kill : 9
kill : 12
kill : 15
kill : 18
kill : 21
kill : 24
kill : 27
kill : 30
kill : 33
kill : 36
kill : 39
kill : 1
kill : 5
kill : 10
kill : 14
kill : 19
kill : 23
kill : 28
kill : 32
kill : 37
kill : 41
kill : 7
kill : 13
kill : 20
kill : 26
kill : 34
kill : 40
kill : 8
kill : 17
kill : 29
kill : 38
kill : 11
kill : 25
kill : 2
kill : 22
kill : 4
kill : 35
[16, 31]