问题:
据说著名犹太历史学家 Josephus 有过以下的故事:
在罗马人占领桥塔帕特后,39个犹太人与 Josephus 及他的朋友躲到一个洞中,
39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,
由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,
直到所有人都自杀身亡为止。然而 Josephus 和他的朋友并不想自杀,
问他俩安排的哪两个位置可以逃过这场死亡游戏?
解答:
模拟推导:
使用collections模块deque进行模拟:
import collections
def ysf(a, b):
d = collections.deque(range(1, a+1)) # 将每个人依次编号,放入到队列中
while d:
d.rotate(-b) # 队列向左旋转b步
print(d.pop()) # 将最右边的删除,即自杀的人
if __name__ == '__main__':
ysf(41,3) # 输出的是自杀的顺序。最后两个是16和31,说明这两个位置可以保证他俩的安全。
数学推导:
n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始): k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2,并且从k开始报0。
假设x是最终的胜利者,逆推的话容易得到 x’=(x+k)%n ,可以以此逆推到最开始的位置。
# 递归直接求出
def ysf(m,k):
if m == 1:
return 0
else:
return (ysf(m-1, k) +k) % m
ysf(41, 3) + 1
# 遍历求出结果
def ysf(m, k):
s = 0
for i in range(2, m+1):
s = (s + k) % i
return s
ysf(41, 3) + 1