练习题 3.10 -- Josephus问题

这是一个Josephus问题
http://en.wikipedia.org/wiki/Josephus_problem上面有如下的说法。
There are n people standing in a circle waiting to be executed. After the first man is executed, k − 1 people are skipped and the k-th man is executed. Then again, k − 1 people are skipped and the k-th man is executed. The elimination proceeds around the circle (which is becoming smaller and smaller as the executed people are removed), until only the last man remains, who is given freedom.
The task is to choose the place in the initial circle so that you survive (are the last one remaining), given n and k.

翻成中文
http://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98
有n个囚犯站成一个圆圈,准备处决。首先从一个人开始,越过k − 2个人,并杀掉第k个人。接着,再越过k − 1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。
问题是,给定了n和k,一开始要站在什么地方才能避免被处决?

对于k=2的情况,有下面这样的定理,具体的证明过程,参考wiki
定理: 如果n = 2m + l 0/leq l<2^m ,则f (n ) = 2l + 1

我用很笨拙的链表实现的一个

  1. void  josephuse(list **p,  int  n,  int  k)
  2. {
  3.     list    *before, *next, *cur;
  4.      int      counter;
  5.     assert(NULL != p);
  6.     assert(NULL != *p);
  7.     before = cur = *p;
  8.     k = k % n;
  9.     counter = 0;
  10.      while (cur) {
  11.         counter++;
  12.          if ( counter == k) {
  13.             n--;
  14.             counter = 0;
  15.             printf( "deleting pos %d/n" , cur->pos);
  16.             before->next = cur->next;
  17.             free(cur);
  18.             cur = before->next;
  19.              if ( 1 == n)  break ;
  20.              continue ;
  21.         }
  22.         before = cur;
  23.         cur = cur->next;
  24.     }
  25.     printf( "last pos is %d/n" , before->pos);
  26. }

全部的的程序

  1. #include 
  2. #include 
  3. #include 
  4. #include 
  5. typedef   struct  list_t list;
  6. struct  list_t {
  7.      int      pos;
  8.     list*   next;
  9. };
  10. void  josephuse(list **p,  int  n,  int  k)
  11. {
  12.     list    *before, *next, *cur;
  13.      int      counter;
  14.     assert(NULL != p);
  15.     assert(NULL != *p);
  16.     before = cur = *p;
  17.     k = k % n;
  18.     counter = 0;
  19.      while (cur) {
  20.         counter++;
  21.          if ( counter == k) {
  22.             n--;
  23.             counter = 0;
  24.             printf( "deleting pos %d/n" , cur->pos);
  25.             before->next = cur->next;
  26.             free(cur);
  27.             cur = before->next;
  28.              if ( 1 == n)  break ;
  29.              continue ;
  30.         }
  31.         before = cur;
  32.         cur = cur->next;
  33.     }
  34.     printf( "last pos is %d/n" , before->pos);
  35. }
  36. #define LEN     1000
  37. #define KTH     2
  38. int  main( void
  39. {
  40.      int      i;
  41.     list    *p,*tmp, *last;
  42.      /* malloc head */
  43.     p = (list*)malloc( sizeof (list));
  44.      if (!p)  return  -1;
  45.     p->pos = 0;
  46.     p->next = NULL;
  47.     last = p;
  48.      /* alloc 9 more */
  49.      for (i = 1; i < LEN; i++) {
  50.         tmp = (list*)malloc( sizeof (list));
  51.          /* take care the memory allocated are not freed by hand */
  52.          if (!tmp)  return  -1;
  53.         last->next = tmp;
  54.         tmp->pos = i;
  55.         tmp->next = NULL;
  56.         last = tmp;
  57.     }
  58.     last->next = p;
  59.     josephuse(&p, LEN, KTH);
  60.      return  EXIT_SUCCESS;
  61. }

验证
N     K     last
10    2     5 - 1   
1000  2     977 - 1
1000  3     604 - 1

找到了网上更好的算法如下2009/6/2

#include #include int King(int M, int N) { int i, k; for (i = 2; i <= M; i++) k = (k + N) % i; return ++k; } int main(void) { int m,n; printf("Inpurt two numbers: "); scanf("%d %d", &m, &n); printf("out of king is %d /n", King(m, n)); return 0; }

 

你可能感兴趣的:(练习记录)