易飞滔Todd | 次生进化

Josephus问题c++代码

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而 Josephus 和他的朋友并不想遵从,Josephus要 他的朋友先假装遵从,他将朋友与自己安排在第16个与第35个位置,于是逃过了这场死亡游戏。这个游戏产生的一般性问题只能采用递推的方法解决,只有在特殊情况下才有好的显式表示。以下的代码算法用到了该文献中的公式。

/* 文献 1. Lorenz Halbeisen Eth et al., “The Josephus Problem,” J. THOR. NOMBRES BORDEAUX 9 (1997): 303--318. 给出了递推公式的推导并讨论了显示表示,其中间隔k=2时有很好的结果。 J(n,k,i)表示大小为n的环,从标号0开始,每k个杀一个,第i个被杀的人的编号。 */ 
#include <iostream> using namespace std; 
bool JosephusSimulate(int size, int step)//过程模拟 
{ 
  bool *ring=new bool[size]; 
  for(int i =0; i<size; i++) 
    ring[i]=true;//构造大小为size的动态数组 
  int indicator = -1; //数数的杀手指到的编号0~size-1 
  int counter = 0; //循环计数器 
  int surviver=size; //幸存者数目 
  while(surviver>0) //杀光光? 
  { 
    indicator = (indicator+1)%size; 
    if(ring[indicator]== true) //活人算算杀不杀 
    { 
      counter = (counter+1)%step; //循环计数1~step(=0) 
      if(counter==0) 
      { 
        ring[indicator] = false;//杀人啦 
        cout <<indicator+1 <<",";//数组的编号是从0开始的,转换为1开始 
        surviver--; 
      } 
    } 
  } 
  delete[] ring;//销毁数组 
  ring = NULL; 
  return true; 
} 

int JosephusRecursion(int size, int step, int order)//递推算法, 
{ 
  //公式 J(n,k,1)=(k-1)mod n 
  // J(n+1,k,i+1)=(k+J(n,k,i))mod(n+1), 
  int indicator=(step-1)%(size-order+1); 
  for(int i=size-order+2; i<=size; i++) 
  { 
    indicator = (indicator+step)%i; 
  } 
  return indicator+1;//数组的编号是从0开始的,转换为1开始 
} 

int Josephus2(int size,int order)//step=2时的快速算法 
{ 
  //公式来自参考文献1 c=2(n-i)+1 
  //J(n,i)=2*(n-c*2^(log2(n/c))) 对数取下整 
  //2^(log2(n/c))作为整体计算,找小于且接近n/c的2的次幂 
  int c = 2*(size-order)+1; 
  int nc = size/c; int i=0; 
  while(nc>0) 
  { 
    nc = nc>>1; i++; 
  } 
  int indicator = (2*size) - (c<<i); 
  return indicator+1; 
} 

int main() 
{ 
  int size,step,order; 
  cout << "size?"; 
  cin >> size; 
  cout << "step?"; 
  cin >> step; 
  cout << "order?"; 
  cin >> order; //JosephusSimulate(size,step); 
  for(int i=1; i<=size; i++) 
  { 
    cout << JosephusRecursion(size,step,i) << endl; 
  } 
  //cout << Josephus2(size,order) << endl; return 0; }