- Description
约瑟夫问题是一个非常经典的问题,它的问题描述是:有 n 个人围成一圈,从第 1 个人开始,每次按顺时针方向向后选择第 m 个人,并将这个人出列。那么你能高效的算出出列的顺序吗?
- Input
输入数据有多组,每组输入数据为一行,两个正整数 n和m (1<=n,m<=30000)
- Output
每组输出只有一行,表示出列的顺序。每两个数字之间用一个空格分开。
- Sample Input
4 2
5 3
- Sample Output
2 4 3 1
3 1 5 2 4
#include<iostream>
using namespace std;
#define R(r) ((r)<<1|1)
#define L(r) ((r)<<1)
#define Mid(x,y) (((x)+(y))>>1)
#define M 30000+10
struct tree
{
int x,y,num;
}t[3*M];
void build(int x,int y,int r)
{
t[r].x=x;
t[r].y=y;
t[r].num=y-x+1;
if(x==y) return ;
build(x,Mid(x,y),L(r));
build(Mid(x,y)+1,y,R(r));
}
int find(int k,int r)
{
t[r].num--;
if(t[r].x==t[r].y) return t[r].x;
if(k<=t[L(r)].num)
return find(k,L(r));
else
return find(k-t[L(r)].num,R(r));
}
int main()
{
int n,m,i,pre;
while(scanf("%d%d",&n,&m)==2)
{
build(1,n,1);
pre=((m%n)?m%n:n);
printf("%d",find(pre,1));
for(i=1;i<n;i++)
{
pre=(pre-1+m)%(n-i);
pre=pre?pre:n-i;
printf(" %d",find(pre,1));
}
puts("");
}
return 0;
}