poj 2244 约瑟夫环

这里在推一遍公式

由于每次都是由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;  
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值