1073 约瑟夫环
http://www.51nod.com/Challenge/Problem.html#!#problemId=1073
N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到K的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。
例如:N = 3,K = 2。2号先出列,然后是1号,最后剩下的是3号。
收起
输入
2个数N和K,表示N个人,数到K出列。(2 <= N, K <= 10^6)
输出
最后剩下的人的编号
输入样例
3 2
输出样例
3
刚开始我也是用的模拟算法,用数组来做的,当连续m个值为0时就把那个数组元素置为count,count表示第几个出列的。所以当count==N时就知道它是最后一个人。
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std ;
int main()
{
vector<int> a;
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
a.push_back(0);
int i=0;
int j=1;
int count=0;
while(1)
{
if(count==m&&count!=0)
{
count=0;
if(i==0)
a[n-1]=j;
else
a[i-1]=j;
if(j==n)
{
if(i==0)
cout<<n;
else
cout<<i;
break;
}
j++;
}
if(a[i]==0)
count++;
i=(i+1)%n;
}
return 0;
}
但是这样子的模拟算法对于小量数据可行,大量数据就给超时了。因为当N非常大时,M也非常大,要找最后两个人谁出列,这样一来大约就要遍历 N*M 次,这就非常复杂了。所以下面我们用数学递推公式:
f(1) = 0
f(n) = (f(n-1)+m)%n (n>1)
公式中编号从0开始,所以题目中的答案是f(n)+1
详细推导过程 : http://book.51cto.com/art/201403/433941.htm
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std ;
int f(int n,int m)
{
if(n==1)
return 0;
return (f(n-1,m)+m)%n;
}
int main()
{
vector<int> a;
int n,m;
cin>>n>>m;
cout<<f(n,m)+1;
return 0;
}