练习题 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 <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <assert.h>
  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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值