问题描述与证明
- 约瑟夫环问题:n个人围成一圈,第一个人从1开始报数,报m的将被淘汰,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
- 递推公式:f(n,m)=[f(n-1,m)+m]%n,其中f(i,j)表示当问题规模为i,报数长度为j时最后胜利者的编号。
- 证明:使用数学归纳法进行证明。
- 当n=1时,f(1,m)=0,因为编号从0开始且只有一个人,胜利者编号显然为0。
当n=2时,序列为0,1,若m为奇数,则胜利者编号为1;若m为偶数,则胜利者编号为0,易有f(2,m)=m%2=(0+m)%2=[f(1,m)+m]%2,结论成立。
- 假设当n=i-1时结论成立,即对于序列0,1,2,...,i-2而言,最后的胜利者编号为f(i-1,m)。
当n=i时,序列为0,1,2,...,i-1。设第一轮的淘汰者编号为k(若m%i=0,则k=i-1,否则k=m%i-1),则序列可表示为0,1,2,...,k-1,k,k+1,...,i-1。第一轮淘汰k,余下的序列x'为k+1,...,i-1,0,1,...,k-1,问题规模变为i-1。
因为由归纳假设,当n=i-1时,对于序列x:0,1,2,...,f(i-1,m),...,i-2,胜利者编号为f(i-1,m)。由于x'=(x+k+1)%i,故f(i,m)=[f(i-1,m)+k+1]%i。当m%i=0时,k+1=i,[f(i-1,m)+k+1]%i=[f(i-1,m)+i]%i=f(i-1,m)%i+0=f(i-1,m)%i+m%i=[f(i-1,m)+m]%i;当m%i!=0时,k+1=m%i,[f(i-1,m)+k+1]%i=[f(i-1,m)+m%i]%i=[f(i-1,m)+m]%i。故当n=i时,结论成立。
综上,命题成立。
- 感想:因为当n=i-1时,对于序列x:0,1,2,...,f(i-1,m),...,i-2,胜利者编号为f(i-1,m)。对于问题规模为i时,经过第一轮淘汰,得到序列x'。只要能够发现x与x'间的对应关系,由f(i-1,m)就能得到f(i,m)。
代码
class Solution {
public:
int lastRemaining(int n, int m) {
int res=0;
for(int i=2;i<=n;i++)
res=(res+m)%i;
return res;
}
};