约瑟夫问题的一些解法
约瑟夫问题:
有n个人,编号为
算法1(Simple算法):
用队列模拟,可以算出每一次出队的人。
时间复杂度
当n很小而m很大时,可以通过取膜将
注:
编号整体
编号整体
算法2:
设
所以发现递推式:
然后如果
如果是个奇数,下一次会让1号出去,我们就可以直接把1号移出去然后把其它的奇数编号重编号
所以发现了递推公式:
时间复杂度
算法3,4的代码:
/*
Author: CNYALI_LK
LANG: C++
PROG: mayuri.cpp
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define all(x) x.begin(),x.end()
#define end(...) {printf(__VA_ARGS);exit(0);}
using namespace std;
const double eps=1e-8;
const double PI=acos(-1.0);
typedef long long ll;
template<class T>void chkmin(T &a,T b){a=a<b?a:b;}
template<class T>void chkmax(T &a,T b){a=a>b?a:b;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
int yues(int x){//m=2
if(x==1)return 1;
else if(x&1)return 2*yues(x>>1)+1;
else return 2*yues(x>>1)-1;
}
int main(){
freopen("mayuri.in","r",stdin);
freopen("mayuri.out","w",stdout);
int T;
scanf("%d",&T);
while(T){
int n,m;
scanf("%d%d",&n,&m);
int s=1,t=1,k;
while(t<=n){
k=(t-s)/(m-1);
if(t+k>=n){
s=s+m*(n-t);
printf("%d\n",s);
break;
}
s+=m*k;//压缩多个(+ m-1) mod n + 1
t+=k;
++t;
s=(s+m-1)%t+1;
}
--T;
}
return 0;
}