LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4200|回复: 6

[算法]Josephus相关问题。

[复制链接]
发表于 2006-8-22 15:43:33 | 显示全部楼层 |阅读模式
传说是这样地:
在Jewish-Roman战争时期,著名的历史学家Josephus与一些犹太叛乱者被罗马的军队围困在一个山洞里,这些叛乱者宁为玉碎不为瓦全,决定以自杀作为最后的抗争手段,但是Josephus不想死阿,所以非常有数学天赋的他就提出了一个方案让自杀变得有"趣"些:让我们围成一个圆圈,然后从第一个人开始计数,每次杀掉第2个人,直到剩下最后一个,他再自杀。毫无察觉的众人轻率的答应了,而万万没有想到阴险的Josephus早就计算好了自己所要站在的位置,使得最后剩下的人就是他自己,当然至于后来Josephus去投降来保全自己的生命已经是另外的一个故事了,那么问题就是,对于n个人,最后剩下的是谁呢?
对于5个人的情况是这样地:
1,2,3,4,5
依此杀掉2,4,1,5
最后剩下的是3
发表于 2006-8-22 15:51:41 | 显示全部楼层
一直以为Josephus游戏是小孩子玩的,原来背后是个阴谋啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-8-22 15:55:58 | 显示全部楼层
传统的Josephus问题已经说完了,那么开始介绍几个相关的变形问题。
相关问题一般都与两个参数有关,一个是总人数n,一个是杀人步长m,所谓的杀人步长就是
从1开始计数,每次杀掉第m个人,然后从被杀掉的人的下一个人开始从1计数,再杀掉第m个人,依此直到剩下最后一个。
下面有3个相关的变形问题:
1.总共有n个人,杀人的步长为m,问编号为k的人,第几个被杀掉?
2.总共有n个人,杀人的步长为m,问第k个杀掉的人,编号是多少?
3.总共有n个人,问最小的使得前n/2次杀掉的都是[n/2] ..n中的人的杀人步长是多少?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-8-22 15:58:06 | 显示全部楼层
Post by Lolita
一直以为Josephus游戏是小孩子玩的,原来背后是个阴谋啊
对阿, 所以这个问题一般的称谓是:臭名昭著的约瑟夫问题----the  notorious Josephus problem
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-8-22 17:48:46 | 显示全部楼层
第一问:存在O(n)的算法
第二问:存在O(n)的算法
第三问: 第三问存在....汗,一般只能解决n < 14的问题。(O(n^2 * n!)
具体题目参见:
1.topcoder SRM 315 div 2 hard problem
2.百度A*程序大赛,复赛第1题(稍微有些变化)
3.Poj1012
回复 支持 反对

使用道具 举报

发表于 2009-4-23 20:20:00 | 显示全部楼层
偶然再看到这个帖子,又偶然看到第3题,恰好是上个月无意逛POJ看到的。当时想了大约1小时吧,提交上去就AC了, 我可不是ACM选手,纯粹是为了好玩。
贴个我求杀人步长的解法,不是很好,恰好满足 k<=14 的POJ要求。

POJ那题描述和Iambitious兄的略微不同,简单来说就是一共有2k个人,要求杀k次,且每次都杀死排在最后的k个坏人之一,求杀人步长m
  1. /*
  2. 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.
  3. 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.
  4. */
  5. #include <stdio.h>
  6. #define BOOL int
  7. #define TRUE 1
  8. #define FALSE 0
  9. #define M_MAX 15000000
  10. #define K_MAX 15
  11. BOOL pick(int k, int m)
  12. {
  13.     int i;
  14.     int currpos=0;
  15.     int nextpos;
  16.    
  17.     for(i=0;i<k;i++)
  18.     {
  19.         nextpos=(currpos+(m-1)%(2*k-i)) % (2*k-i);
  20.         if(nextpos<k) return FALSE;
  21.         currpos=nextpos;
  22.     }
  23.    
  24.     return TRUE;
  25. }
  26. int main()
  27. {
  28.     int k;
  29.     int m;
  30.    
  31.     for(k=1;k<=K_MAX;k++)
  32.     {
  33.         for(m=k+1;m<M_MAX;m++)
  34.         {
  35.             if(pick(k,m)==TRUE) break;
  36.         }
  37.         
  38.         if(m<M_MAX)
  39.         {
  40.             printf("k=%d m=%d\n",k,m);
  41.         }
  42.         else
  43.         {
  44.             printf("m not found while k=%d, with limitation m<=%d\n",k, M_MAX);
  45.         }
  46.     }
  47. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2009-4-23 20:28:32 | 显示全部楼层
此外, Iambitious 兄说的第3题时间复杂度为 O(n^2 * n!),不知道如何算出来的?我上面的算法时间复杂度最坏为 M_MAX*O(k)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表