Lazy loaded image
约瑟夫斯问题(Josephus problem)
Words 880Read Time 3 min
2026-2-14
2026-2-14
type
Post
status
Published
date
Feb 14, 2026
slug
Josephusproblem
summary
tags
算法笔记
阅读笔记
category
笔记
icon
password
🌟
约瑟夫斯问题(Josephus problem)
弗拉瓦斯·约瑟夫斯(Flavius Josephus)的名字命名的。约瑟夫斯是一个著名的犹太历史学家,参加并记录了公元66-70年犹太人反抗罗马的起义。约瑟夫斯作为一个将军,设法守住了达伯特的堡垒达47天之久,但在城市陷落了以后,他和40名顽强的将士在附近的一个洞穴中避难。在那里,这些反抗者表决说“要投降毋宁死”。于是,约瑟夫斯建议每个人应该轮流杀死他旁边的人,而这个顺序是由抽签决定的。约瑟夫斯有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品一起投降罗马

一、核心递推关系理解

约瑟夫斯问题 J(n)是:n个人围成一圈,从1号开始每隔一人消去一人,求最后幸存者的初始编号。如将 n分为偶数和奇数来推导。
J(n)是什么?
J(n)是一个函数,它表示约瑟夫斯问题在总人数为 n时的幸存者编号例子:J(1) = 1(只有一个人,他直接幸存)。J(5) = 3(5个人玩这个游戏,最后活下来的是最初编号为3的人)。 所以,J()就是这个游戏的“答案”函数。
  1. n为偶数时(共n = 2k人):
    1. 过程:第一轮会消去所有编号为偶数的人(2,4,6…)。会剩2k - k = k个人,并且他们的编号会是连续的奇数:1,3,5……,2k-1。
    2. 接下来:然后从3号(原始编号)开始继续淘汰,这又是一个规模为K的新一轮。我们可以发现,原始编号现在在新一轮里位居第二位,也就是可以得到一个关系:原编号 = 2 * 新编号 -1
    3. :新游戏中的幸存者编号是J(K)。则有原游戏场次编号:2 * J(K) - 1。即:J(2K) = 2J(K)-1
      1. 即:2K个人玩这个游戏,最后活下来的是最初编号为2 * J(K) - 1的人
  1. n为奇数 (n = 2k + 1):
    1. 过程:第一轮消去所有偶数编号的人(2, 4, 6,..., 2k),紧接着会消去下一个位置,即 1号。剩下 k 个人,编号为:3, 5, 7, ..., 2k+1。
    2. 关键观察:接下来从3号开始继续,形成一个规模为 k的新游戏。此时新编号原编号的关系变为:原编号 = 2 * 新编号 + 1
    3. 推导:新游戏的幸存者编号是 J(k),对应回原编号为 2 * J(k) + 1。因此得到:J(2k + 1) = 2J(k) + 1
🌟
简单记忆:偶数减1,奇数加1。这是由第一轮消去后起始位置和编号重映射的差异导致的。

二、如何通向闭合式与二进制循环移位

有了递推公式和初始条件 J(1)=1,就可以计算任意 n的解。我们可以通过列出前几个值来发现模式:
📢
发现规律
n
1
2
3
4
5
6
7
8
9
10
11
……
J(n)
1
1
3
1
3
5
7
1
3
5
7
观察 J(n)的序列,一个惊人的模式出现了:
  • J(6) = J(110₂) = 101₂ = 5
  • J(7) = J(111₂) = 111₂ = 7
  • J(10) = J(1010₂) = 0101₂ (即101₂) = 5
📌
规律
J(n)的数值,恰好等于将 n的二进制表示 向左循环移动一位(把最高位移到最低位)所得到的值。
为什么会出现循环移位?
这与递推公式 J(2k)=2J(k)-1J(2k+1)=2J(k)+1在二进制下的操作有关。
  • 在二进制中,2 * J(k)相当于 J(k)左移一位(后面添一个0)。
  • 1+1的操作,在特定情况下(结合 J(k)的奇偶性)等价于处理最高位和最低位。
  • 递归地应用这两个公式,其整体效果在二进制视角下,就完美地呈现为一次循环左移。

三、总结与理解路径

  1. 建立递推:通过分析第一轮消去后如何“缩编”为一个小规模的问题,并找到新旧编号的映射关系,从而得到 J(2k)J(2k+1)的递推式。
  1. 发现模式:利用递推式或直接模拟,计算出小 n值对应的 J(n),观察其与 n的二进制表示之间的关系,猜想到“循环左移”的优雅闭合式。
  1. 内在联系:递推公式中的“乘2”对应二进制左移,“±1”对应调整最低位。递归执行整个过程,在二进制上就表现为最高位被移到了最低位。
上一篇
生成组合对象的算法之生成子集
下一篇
从 Heo 到 Heo Pro