這裏在推一遍公式
由於每次都是由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;
}