约瑟夫环问题
n 个人(编号 0 ~ n-1)围成环,从 0 开始报数(最开始从编号 0 开始),报到(m-1)的退出,剩下的人继续从 0 开始报数(从退出的人下一个人开始)。求最后留下来的人的编号。
解法:
- 用数组或者链表模拟整个过程。
- 数学推导。
这里就只写数学推导的方法了。
第一次:从 0 开始报数,(m-1) mod n 出圈。
第二次:从 m mod n 开始报数,假设 k = m mod n,这里形成了新的约瑟夫环 k, k+1, …, n - 1, 0, 1, 2, …, k-2。将编号整体减 k 模 n - 1,得到 0, 1, 2, … , n-2,这又变成了 n-1 个人的约瑟夫环问题了。
由此类推,可以得知约瑟夫环问题存在递推关系。
设 i 个人报 m 个数情况下的胜者编号为 f[i],可以轻易地得出以下递推关系:
- f[1] = 0
- f[i] = (f[i-1] + m) mod i (i > 1)
于是便可以容易地编写出代码了。
1 | int Josephus(int n, int m) |