约瑟夫问题:
n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开
始报数。求胜利者的编号。
用数学方法解的时候需要注意应当从0开始编号,因为取余会等到0解。
实质是一个递推,n个人中最终剩下来的序号与n-1个人中剩下来的人的序号有一个递推关系式。
分析如下:
假设我们第m-1个人退出。
0, 1, 2, 3, ..., m-2, m-1, m, ..., n-1 //original sequence (1)
0, 1, 2, 3, ..., m-2, , m, ..., n-1 //get rid of kth person (2)
m, m+1, ..., n-1, 0, 1, ..., m-2 //rearrange the sequence (3)
0, 1, ..., n-m-1, n-m, n-m+1, ..., n-2 //the n-1 person (4)
我们假设f(n)的值为n个人中最后剩下来的人的序号,则
注意到(2)式(3)式(4)式其实是同一个序列。
观察(1)式和(4)式,可以看出这两个序列是同一个问题,只是人数不同而已。
假设我们已知f(n-1),即(4)式中最后剩下来的人的序号,则(3)式所对应的序号,就是f(n),即(1)式n个人中最后剩下来人的序号。
从(3)式和(4)式,我们不难得出这样一个递推公式:
f(n) = (f(n-1) + m) % n
当n=1时,显然,f(1) = 0
于是递推得f(n)
具体实现代码:
循环:
int Joseph(int n, int m)
{
int result = 0;
for (int i=2; i<=n; ++i)
{
result = (result+m)%i;
}
return result;
}
int Joseph(int n, int m)
{
if(n==1)
return 0;
return ((Joseph(n-1,m)+m)%n);
}