这里在推一遍公式
由于每次都是由1开始,所以可以把1排除掉,直接将城市数变成k-1,把2当作1.
假设上一轮选中k=ANS[I-1],那么剩下的从k+1开始:
<p><pre name="code" class="cpp">//k+1 1
//…… <span style="white-space:pre"> </span>……
//n n-k
//n+1 (就是原来的1) n-k+1
//…… ……
//k+n-2 n-1
//本轮X 下一轮X‘
但是本轮只剩下n-1个数了,而编号还是从1~n(中间缺少了ANS[i-1]),中断了,而下一轮是连续的
所以重新排序成1~n-1,否则从下一轮转换回本轮数字对不上
下一轮转本轮 X = X’+K = X'+ANS[i-1]
再重新得出顺序 a = (X-2)%(n-1)+1 这样原来本轮的编号就由1、2、……ANS[i-1]-1、ANS[I-1]+1、……n 变成1~n-1
合起来a = (X'+ANS[I-1]-2)%(N-1)+1。
如果知道下一轮选中的数在下一轮中的位置X',那么就可以知道该数在本轮的位置a
X’ = (m-1)%(n-1)+1
而这个a就是ANS[I],如果ANS[I]==1,就是选中的城市Ulm,m不符合
#include<iostream>
#include<map>
#include<string>
#include<algorithm>
#include<fstream>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<math.h>
using namespace std;
#define lch(i) ((i)<<1)
#define rch(i) ((i)<<1|1)
#define sqr(i) ((i)*(i))
#define pii pair<int,int>
#define mp make_pair
#define FOR(i,b,e) for(int i=b;i<=e;i++)
#define FORE(i,b,e) for(int i=b;i>=e;i--)
#define ms(a) memset(a,0,sizeof(a))
const int maxnum =21252;
const int mod = 10007;
int n;
//
//#define _DEBUG_
int main()
{
#ifdef _DEBUG_
fstream fin("G:/1.txt");
#else
#define fin cin
#endif
int Joseph[150]={0}; //打表,保存各个k值对应的m值
int k;
while(fin>>k)
{
if(!k)
break;
if(Joseph[k])
{
cout<<Joseph[k]<<endl;
continue;
}
int ans[150]={0}; //第i轮杀掉 对应当前轮的编号为ans[i]的人
//PS:每一轮都以报数为“1”的人开始重新编号
n=k-1;
int m=1; //所求的最少的报数
int flag = 2;
for(int i=1;i<n;i++) //杀n-1次都不是1就可以了
{
if(!ans[i-1])
ans[i]=(m-1)%(n-i+1)+1;
else
ans[i]=(ans[i-1]+m-2)%(n-i+1)+1; //n-i为剩余的人数
if(ans[i]==1){//杀掉了1
i=0;
m++;
}
}
Joseph[k]=m;
cout<<m<<endl;
}
return 0;
}