Josephus 可以用以下算法求解:
int josephus(int n, int k) { if (n == 1) return 1; else return (josephus(n - 1, k) + k-1) % n + 1; }
不过,我也想知道游戏中第i个被杀的人是谁。例如,n=10,k=2,第一个被杀的人就是第二个。我怎样才能得到这个答案?无论如何我可以使用上面的算法找到它吗?
n
人围成一圈,按0
顺时针n-1
方向编号。从有 number 的人开始0
,每隔m
-th 执行一次,下面的程序给出k
第 -th 被杀的人的号码。k
从0
.
def solve(n,m,k):
if m==1: return k
i = (k+1)*m-1
while i>=n:
i = (m*(i-n))//(m-1)
return i
我//
用来表示floor divison
。
假设每个人都将从 开始计数0
,谁报告m-1
是第0
-th 个被杀的人。谁报告2m-1
是第1
-th 个被杀的人,依此类推。
说有人报道i
。他最后的报告是j
。当他报告j
时,有j//m
死有n-(j//m)
活。
所以i = (n - (j//m)) + j
->j-j//m = i-n
假设j = am + b; 0<=b<m-1; a,b is int
,请注意这里,b!=m-1
因为他不会死。
然后a(m-1) + b = (i-n)
。使用 bezout 引理和扩展欧几里得算法,我们得到a=-c; b=(i-n)+c*(m-1); with any int c
. 并且b
在区间 中只有一个解[0,m-1)
,也((i-n)+c*(m-1)) %(m-1)
就是我们需要的解,等于(i-n)%(m-1)
。之后,您可以计算j=(i-n) + (i-n)//(m-1) = (m*(i-n))//(m-1)
.
通过这个递推关系,你可以计算出任何k
第-个被杀的人。
时间复杂度O(mlg(mk))
与空间O(1)
。
如果m
非常大,您可以使用 RedBlackTree 来实现 O(nlg(n)) 时间复杂度。
from sortedcontainers import SortedList
def simulate(n, m):
# all index from 0
people = SortedList(range(n))
idx = 0
while len(people)>0:
idx = (idx+m-1)%len(people)
yield people.pop(idx) # yield executed people number in order
return