poj 2244 约瑟夫环

来源:互联网 发布:模特 李荣浩 知乎 编辑:程序博客网 时间:2024/06/03 21:19

这里在推一遍公式

由于每次都是由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>……//nn-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#endifint 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){//杀掉了1i=0;m++;}        }          Joseph[k]=m;          cout<<m<<endl;      }      return 0;  } 



1 0
原创粉丝点击