问题引入
In computer science and mathematics, the Josephus problem (or Josephus permutation) is a theoretical problem related to a certain counting-out game.
People are standing in a circle waiting to be executed. Counting begins at a specified point in the circle and proceeds around the circle in a specified direction. After a specified number of people are skipped, the next person is executed. The procedure is repeated with the remaining people, starting with the next person, going in the same direction and skipping the same number of people, until only one person remains, and is freed.
The problem — given the number of people, starting point, direction, and number to be skipped — is to choose the position in the initial circle to avoid execution
约瑟夫是公元一世纪著名的历史学家。在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人俘虏,于是决定了一个流传千古的自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报到第3人该人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止。
Josephus problem是一个非常有意思的问题,理解起来很简单,但是要解决却不是太容易。以前在程序课上接触过这个问题,当时的解决方法非常暴力,直接模拟整个游戏过程来得到最终答案。最近读到《具体数学》再次接触到了这个问题,书中的解法确有让人拍案而起的欲望。下面从该问题最基础的类型说起,一步一步解释书中的解法。
基础问题
现有一个n节点的圆圈,且从1到n有序排列。从1开始计数,每隔一个节点去除一个节点,问最后剩下的节点(下面简称幸存者)序号是多少?
Figure 1
要解决这个问题,可以从递归的角度来考虑,这一点在图1中有很直观的表达。针对我们的问题,我们要求解的是幸存者序号,不妨表示为$f(n)$,根据n的奇偶性可以得到下面的关系
现在的问题是如何根据上面的关系求出$f(n)$的表达式。首先不妨从一些简单的例子观察一下规律
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
$f$ | 1 | 1 | 2 | 1 | 2 | 3 | 4 | 1 |
看起来是有一定规律的,写成下面这样也许更清晰
n | $2^0$ | $2^1$ | $2^1+1$ | $2^2$ | $2^2+1$ | $2^2+2$ | $2^2+3$ | $2^3$ |
---|---|---|---|---|---|---|---|---|
$f$ | 1 | 1 | 3 | 1 | 大专栏 Josephus Problem>3 | 5 | 7 | 1 |
简单的归纳就是$f(n) = 2l+1, n=2^m+l$,下面用数学归纳法来证明这一结论
现在我们已经有了$f(n)$的显式表达,不过更令人兴奋的是我们可以用一种更为简洁美观的方式来表达这一结果。
第一次看到上面的结果,我确实很开心,感觉这种形式很漂亮。不过让我更惊喜的是不仅在基础情况下,在复杂的情况下我们也可以利用上面的形式来求解递归式。
为了叙述简便,把递归式中$f(dn)$ 中d称为step,下面一般化以d为基础
问题一般化
Step=2
- step=2与上面解决的问题有很大重合,问题形式化表达如下问题2与问题1的唯一区别是对$alpha,beta_j$进行了一般化,在问题1中$alpha=1,beta_0=-1, beta_1=1$
可以看到,我们再次利用二进制形式写出了任意$f(n)$的解表达式。不过需要注意的是这里的二进制与一般意义上的二进制表达式有一定区别,这里在某个二进制位上的数值可能取0,1之外的值
Step = d, d>1
- 这里对step一般化,取任意大于1的整数值,问题形式化表达如下
- 问题3是最一般化的形式,从最后结果来看,问题3中定义的递归表达式将一个d进制的数映射到了另一个c进 制的数