本人比较笨,约瑟夫问题的求解方法想了好久才想通,在这里留一篇文章,记录一下。
约瑟夫问题:n个人,数m,列出顺序。
1,用算法模拟数数过程,通过一个一个的排除,最后得到最终的结果:
首先解决思路问题,每次数数m个,一共数n次,所以一共经过n*m次,然后定义一个int t,用来算作每个人报数的时候报出的数,
然后没报一下,判断所在的是否还存在,只有两个问题,一个是是否到了末尾,如果到了末尾就转到前面去;然后判断是否已经数出,如果数出,直到
没有数出的数为止做while循环。每次做完一个m,就要归零(输出一个被数出的人),因为是从零开始的,所以输出的人要加上1.
for(int i=0;i<n;i++){
for(int i0=0;i0<m;i0++){//此为一共计算的n*m次
t++;//报数
if(t==n) t=0;
while(monkey[t]==0){
t++;
if(t==n) t=0;
}
}
// cout<<t+1<<endl;
monkey[t]=0;
if(i==n-1) cout<<t+1<<endl;;
}
上述的算法s
2.用递推的方法求解:
因为直接要求的最后的一个人用以下形式来表示:
0 1 2 3 4 5 。。。。。 n-1,
在排除第一个人的时候,当n》m时,排除的是第m个,(代号为m-1),当n》m时,第n-m个,排除的是(n-m-1),所以排除的是第m mod n个
再将所有的重新排列一下为
m m+1 m+2 m+3 。。。。n-1 0 1 2 3 。。 m-2,,将其看作从
0 1 2 3 4 。。。。。 n-2,根据前面的算式,转换成n-1个人的约瑟夫问题,如果知道是第x个人是n-1个人约瑟夫问题的最后的人,根据以上的表,就能够知道第n人的约瑟夫问题最后一个人是谁
所以关键就是求出递推关系,怎么从n-1人的约瑟夫问题的解转换到n人约瑟夫问题的解:
n-1个人约瑟夫问题(x)的第二重排除根据n人约瑟夫问题(x‘)来推导,x'=(x+m) mod n
(如果第0是最后胜利者,则m mod n=m为最后胜利者)
以后就是根据递推关系,根据1人约瑟夫问题的解为它本身,求出n人约瑟夫问题的解
#include <iostream>
using namespace std;
int main()
{
int n,m;
while(1){
cin>>n>>m;
if(n==0&&m==0) return 0;
int k=0;
for(int i=1;i<=n;i++){
k=(k+m)%i;
}
cout<<k+1<<endl;//计算从0开始,实际从1开始
}
}