问题简述 见 简单约瑟夫环系列(1)
下面用数学公式推导的方法,解决约瑟夫环经典问题。
第一步,这n个人我们给每一个人一个编号 0 ,1 ,2 ······ n-2,n-1
第二步,当第一轮游戏结束后,这n个人少就变成了n-1个人
第三步,将第一轮结束后剩下的人里面第一个报数的记为K,则这n-1个人 的编号为
k,k+1,k+2······n-2,n-1,0,1,2,······k-2(k-1也就是第一轮结束后出局的那个人)
第四步,也是最关键的一步,这n-1个人我们是不是也可以当成第一步那样重新来个编号,如下:
k,k+1,k+2······n-2,n-1,0,1,2,······k-2
0 ,1 ,2 ······ n-3,n-2(少了一个人所以到n-2)
上面和下面一一对应
于是,问题就转换到了n-1的情况,好了,发现了没,递推!
第五步 我们来推导数学公式。
在四步的转换中k - -> 0,那么当我们从反过来从n-1的情况推n的情况的时候,
如果在n-1情况下X是最后胜出的人,那么在n的情况下 X+k就是最后胜出的人。
由此,得出公式x=(x+k)%n
时间复杂度降低到了O(n)。
下面给出代码。
#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
int n,m;
while(cin>>n>>m){
int lastPeople=0;
for(int i=1;i<=n;i++)
{
lastPeople=(lastPeople+m)%i;
}
cout<<lastPeople+1<<endl;
}
return 0;
}