背景
相传公元一世纪著名犹太历史学家约瑟夫在罗马人占领乔塔帕特後,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
约瑟夫问题描述
设有n个犯人坐成一个圈(编号1~n),从第k(1<=k<=n)个人开始报数,数到m的人将被处决掉,接着从下一个人开始从新报数,数到m的人再被处决,如此循环,直至剩下一名犯人. 求处决犯人的顺序和最后的幸存者编号.
我们可以用代码模拟整个过程从而得出正确的答案:


<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->1


2

3

4

5

6

7

8

9



10

11

12

13

14

15

16

17

18

19



20

21



22

23

24

25

26

27

28



29

30

31

32

33

34

35

36

37



38

39

40

41

42

当然, 这并不是最好最高效的解法.这里我们回到广义的约瑟夫问题来分析一下:
如果有n个人围成一圈而坐,每个人的位置都带编号,编号从1到n(没有重复的),从第k个位置开始数数,当数到m时,那个人退出圈子,再从退出的那个人的下一个位置开始数(假定是顺时针数的),一直到剩下r个人。
进一步分析
n个人玩这个游戏的时候,假设最后剩下的r个人中,其中一个人占据了第p个位置,那当我们以n + 1个人开始玩游戏的时候,显然,这第n + 1个人希望被安排到第p + m个位置,因为如果第p个人是安全的,那么至少这第(p + m)MOD (n + 1)个位置上的人也是安全的,他的理由是“既然现在是n + 1个人玩,仍然只能留r个人,那么只要在n个人剩余的r个人里面有一个人在我之前退出就可以了,所以我要加在这第r个人中某个人的后面m处”。对应的,如果n个人玩的时候,第q个位置上的人退出了圈子,那n + 1个人玩的时候第(q + m)MOD (n + 1)个位置上的人也得退出圈子。根据前面的递推公式,显然我们可以通过逆推得到最终解,原先的约瑟夫函数可以写成如下形式:


<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->





































推论
从上面的分析中已经知道,每次添加一个人到游戏中,原来剩余的那r个人的位置就会“后移”m个单位,因为新加的人使得ta之前的第m个人退出了圈子。所以我们可以进一步地作出这样的推论:
假设n个人玩游戏,最后一个幸存者(即r = 1时)占据了编号为p的位置,而在n + x个人玩的时候,最后一个幸存者占据第y个位置。那么y = (p + mx )MOD (n + x)。
这样我们就可以根据不同的初值n迅速计算出最后一个人的位置了。
参考资料
2.Wikipedia,Josephus Problem,http://en.wikipedia.org/wiki/Josephus_problem
黄季冬
2009年8月4日