0001~约瑟夫问题

Posted dujianfeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0001~约瑟夫问题相关的知识,希望对你有一定的参考价值。

1. 一个杀人游戏
这个问题是以弗拉维奥·约瑟夫命名的,它是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。[1]

2. 数学解法一
传统解法为循环链表模拟出队流程,详见[1]。这里讨论更高效的数学解法。
要求解的是最后剩下的人的编号。解决思路是如果将杀人后的环重新编号,可以让求解的问题仍与杀人前等价,但问题规模(人数n)却可以减小 1,这样只要找到杀人前后新旧编号的递推关系,就可以利用规模为 1 时最后剩下人的编号一定为 0 的特点,反推回更大问题规模时的编号。
囚犯个数为 n,每次杀掉第 m 个人,囚犯编号从 0 到 n - 1
从 0 开始编号是为了下面公式中求余情况简单,不然如从 1 开始编号,当对 n 求余为 0 时要特殊修正为 n,在求解出编号后可以通过加 1 恢复成常见的从 1 开始编号方式
如规模为 n 时某个人 X,对应编号记为 Xn,规模变为 n - 1 时,从被杀的那个人后重新编号,X 的新编号为  Xn-1
可以通过下面的例子看出 Xn-1 与 Xn 相差为被杀的那个人编号加 1,即 m % n, 但考虑 Xn-1 + m % n 后可能超过 n,因此最终关系为 Xn = (Xn-1 + m % n) % n,根据同余性质[2]等价为 Xn = (Xn-1 % n + m % n) % n,等价为 Xn = (Xn-1 + m) % n

对于 n = 5, m = 8
Xn
01234
杀人后
01被杀34
Xn-1
23
01

最后剩下的那个人为 Y,规模为 n 时的编号为 Yn,显然 Y1 = 0,利用 Xn = (Xn-1 + m) % n 即可递推求得 Yn,代码详见[1]
也可推广为求解剩下多个人的问题,比如上面提到的历史上 41 人剩 2 人,设两人为A、B,则 A2 = 0 和 B2 = 1 带入递推公式求得 A41、B41 的值

标红为死的人,每次死人后重新编号
第 1 次死人,规模 n第 2 次死人,规模 n - 1
第 a 次死人
第 n 次死人,规模 1
0 1 ... m % n - 10 1 ... m % (n - 1) - 1
0 1 ... m % (n - a + 1) - 1

最终问题转换为已知小规模时的新编号和新旧编号关系,求解大规模时的旧编号问题。

3. 数学解法二[3]
前面的解法是从某个人的编号和编号变化考虑,这个解法则是从某个人报数时的时刻和时刻变化考虑,这里“时刻”指的是所有人报的数中的第几个,从 0 开始算(为了 b < m - 1下面化简方便
思路为 Y 报数的时刻为 n * m - 1,通过求得 Y 前后两次报数的时刻关系,即可反推回 Y 第一次报数的时刻,而这个时刻就是 Y 的编号

如 Y 在 p 时刻报了数,同时 p 时刻 Y 不会死,即 (p + 1) % m != 0,将前面已经死的人数设为 a,则有 p = a * m + b,0 <= b < m - 1。可以参考下表理解
标红为死人的时刻
第 1 次死人第 2 次死人
第 a 次死人
第 a + 1 次死人
第 n 次死人
0 1 ... m - 1m ... 2m - 1... am - 1am ...p ... am + m - 1  n * m - 1
Y 在 p 时刻后的下一次报数时刻设为 q,q 为 p 在剩下的 n -a 个人报数后,即 q = p + n - a,将等式变为 p 用 q、n、m 表示则得到 p = q - n + (q - n - b) / (m - 1),由 b < m - 1,得到 p = q - n + floor((q - n) / (m - 1)),这样就可从后面的报数时刻求得前面的报数时刻

 

上面两种解法都可以推广为第 j 个被杀的人编号,和第 j 个人被杀后第 k 个报数的人的编号

 

相关资料
[1] 维基百科
[2] 同余性质
[3] 约瑟夫问题解法





















以上是关于0001~约瑟夫问题的主要内容,如果未能解决你的问题,请参考以下文章

约瑟夫问题小结

:链表 -- 单向环形链表约瑟夫问题(约瑟夫环)

约瑟夫问题

约瑟夫环问题

用ArrayList(解决约瑟夫问题)

1139 约瑟夫环问题