用点树 模拟约瑟夫问题

 

 

 

//用点树 模拟约瑟夫问题
//N个人编号:0,1,2, ... N-1,  报数:1到M,报到M的出列
//www.cnblogs.com/flyinghearts 
#include<cstdio> 

template
<int N> struct Round2k {
  
enum { down = Round2k</ 2u>::down * 2
         up 
= down == N ? down : 2 * down };
}; 

template
<> struct Round2k<1> {
  
enum { down = 1, up = 1};
};
 
template 
<int  M, typename T = int>  //区间[0, M)
class  PointTree {
  
enum { Extra = Round2k<M>::up, N = (M + 1 + Extra) / 2u }; 
  T info[N];
public:
  PointTree() { init(); }

  
void init()
  {
    info[
0= M;  //为了快速初始化数据,实际上放了0到Extra-1共Extra个点
    for (int i = Extra / 4u; i < N; ++i) info[i] = 1;
    
for (int i = 2, k = Extra / 4u; k > 0; k /= 2u, i *= 2)
      
for (int j = k; j < k * 2++j) info[j] = i;  
  }
  
  
int erase_nth(int n)
  {
    
if (n >= info[0]) return -1;
    
--info[0];
    
int i = 1;
    
while (i < Extra) {
      
if (n < info[i]) {  --info[i]; i *= 2; }
      
else { n -= info[i]; i = i * 2 + 1; }  
    }
    
return i - Extra;    
  }
  
  
int count(int n) {
    
int sum = 0, i = Extra + n;
    
while (i % 2u)  sum += info[(i /= 2u)];
    
return info[i / 2u- sum;
  }
  
  
void show()
  {
    
for (int i = 0; i < M; ++i)
      
if (count(i)) printf("%2d ", i);
    printf(
"\n");  
  }
}; 

int main()
{
  
const int N = 17;   //N个人编号:0,1,2, ... N-1
  const int M = 7;    //报数:1到M,报到M的出列
  PointTree<N, unsigned char> pt;
  printf(
" total_size: %d bytes\n\n"sizeof(pt));
  
for (int j = N, k = 0; j >= 1--j) {
    k 
= (k + M - 1% j;
    
int t = pt.erase_nth(k);
    printf(
" turn: %2d  out: %2d   rest:  ", N - j, t);
    pt.show();
  }
  printf(
" \n\n");
 
}

 

posted @ 2011-03-31 23:19  flyinghearts  阅读(253)  评论(0编辑  收藏  举报