【原】 POJ 1012 Joseph 约瑟夫 解题报告

http://poj.org/problem?id=1012


共2k个编号,求最小m使得前k次出队的是后k个编号


方法:
1、run1012_1。坏人被kill掉的先后顺序无关紧要,知道下一个踢到的是好人还是坏人就行了。具体见注释
2、run1012_2。由于输入数的范围较小,所以可以打表实现

Description

The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.

Input

The input file consists of separate lines containing k. The last line in the input file contains 0. You can suppose that 0 < k < 14.

Output

The output file will consist of separate lines containing m corresponding to k in the input file.

Sample Input

3

4

0

Sample Output

5

30

 

   1:  
   2: #include <iostream>
   3: #include <fstream>
   4:  
   5: using namespace std ;
   6:  
   7:  
   8: void run1012_1()
   9: {
  10:     ifstream in("in.txt") ;
  11:     
  12:     int k,m ;      //m为移动的个数        
  13:     int left ;     //记录队列中还有多少人
  14:     int cur ;      //cur为移动前的索引,以0为起点
  15:     int i,j ;
  16:     bool found ;   //标志位,当找到适合的m时结束循环
  17:     
  18:     int a[14] = {0} ;  //由于输入数据k为1~13,所以可以记录下计算过的结果,以便下次遇到时直接输出
  19:  
  20:     while( in>>k && k!=0 )
  21:     {
  22:         if( a[k]!=0 )  //该k已经计算过,直接输出不需再计算
  23:         {
  24:             cout<<a[k]<<endl;
  25:             continue ;
  26:         }
  27:  
  28:         found=false ;
  29:         while( !found ) //对特定的k找最小m
  30:         {    
  31:             //key point :
  32:             //m只能为k+1的整数倍或者是k+1的整数倍加1,            
  33:             //因为只剩下K+1个人时,cur索引必位于k或k+1上
  34:             for( i=1 ; !found ; ++i )
  35:             {
  36:                 for( j=0 ; j<=1 ; ++j )  //确定了m值
  37:                 {
  38:                     left = 2*k ;         //初始化人数
  39:                     cur = 0 ;
  40:                     m = (k+1)*i+j ;      //确定某m值
  41:  
  42:                     //************
  43:                     //key point :
  44:                     //kill过程
  45:                     //坏人被kill掉的先后顺序无关紧要,知道下一个踢到的是好人还是坏人就行了。
  46:                     //由于好人一直都是k个,每kill掉一个坏人,坏人数-1,所以队列的总数每次-1但是好人一直是前k个
  47:                     //下一个被kill的人在队列中的“相对”序号为cur_now=(cur_last+m-1)%left+1。
  48:                     //    只要cur_now>k,那么下一个被kill掉的就是坏人,将坏人数-1,并--cur_now,它也就是下一个计
  49:                     //    数起始编号在队列中相对位置的前一位
  50:                     //    但如果cur_now<=k,则下一个被kill的是好人,退出kill的过程。
  51:                     //退出kill过程之后,判断剩下的人数是否为k,若是则证明剩下的都是好人,此m成功。若不是则证明
  52:                     //    在kill掉所有坏人之前会kill掉好人,此m失败
  53:  
  54:                     //例如:k=3,m=5
  55:                     //1 2 3 4 5 6
  56:                     //cur=0,先出队的是5,5也是它在队列中的相对位置,此时队列为 1 2 3 4 6,“相对”的位置编号为 1 2 3 4 5
  57:                     //--cur为4,也就是下一个计数起始编号6在队列中相对位置"5"的前一位
  58:                     //下一个出队的是“相对”位置(4+m-1)%left+1=4,此时队列为 1 2 3 6,“相对”的位置编号为 1 2 3 4
  59:                     //--cur为3,也就是下一个计数起始编号6在队列中相对位置"4"的前一位
  60:                     //下一个出队的是“相对”位置(4+m-1)%left+1=4,此时队列为 1 2 3,“相对”的位置编号为 1 2 3
  61:                     while( true )
  62:                     {
  63:                         cur = (cur+m-1)%left+1 ;  //下一个被kill的人在队列中的“相对”序号
  64:                         if( cur>k )
  65:                         {
  66:                             --left ;
  67:                             --cur ;
  68:                         }
  69:                         else
  70:                             break ;
  71:                     }
  72:                     if(left==k)
  73:                     {
  74:                         a[k] = m ;
  75:                         found = true ;
  76:                         break ;
  77:                     }
  78:                    //*************
  79:  
  80:                 }  //END :             for( j=0 ; j<=1 ; ++j )
  81:             }      //END :         for( i=1 ; !found ; ++i )
  82:         }          //END :     while( !found )
  83:         cout<<m<<endl;
  84:     }              //END : while( in>>k && k!=0 )
  85: }
  86:  
  87: //打表
  88: void run1012_2()
  89: {
  90:     ifstream in("in.txt");
  91:     __int64 a[14]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881};
  92:     
  93:     int k ;
  94:     while( in>>k && k!=0 )
  95:         cout<<a[k]<<endl;
  96: }
  97:  
  98: void GetAllM()
  99: {
 100:     int k ;
 101:     int n,m ;
 102:     int r,h ; 
 103:     int kill ;
 104:     int left ;
 105:     bool found ;
 106:  
 107:     //得出所有k情况的m
 108:     for( k=1 ; k<14 ; ++k )
 109:     {
 110:         n = 2*k ;
 111:         found = false ;
 112:         while( !found )
 113:         {    
 114:             // m%2k>k ---> m=2k*r+h,h>k
 115:             for( r=0 ; !found ; ++r )
 116:             {
 117:                 for( h=k+1 ; h<=2*k ; ++h )
 118:                 {
 119:                     m = 2*k*r+h ;
 120:                     left = n ;            
 121:                     kill = (m-1)%n+1 ;  //第一个被kill的编号
 122:                     --left ;            //少了一个人
 123:                     while(true)
 124:                     {
 125:                         kill = ( kill + (m-1) -1 )%left+1 ;  //下一个被kill的编号
 126:                         if(kill<=k)
 127:                             break ;
 128:                         else
 129:                             --left ;
 130:                     }
 131:                     if( left==k )
 132:                     {
 133:                         found = true ;
 134:                         break ;
 135:                     }
 136:                 }
 137:             }
 138:         }
 139:         cout<<k<<"\t"<<m<<endl;
 140:     }
 141: }
posted @ 2010-11-04 21:04  Allen Sun  阅读(506)  评论(0编辑  收藏  举报