1 递归问题
递归问题的特性是每一个问题的解都依赖于同一问题的更小实例的解。
1.1 河内塔(汉诺塔)
1.1.1 递归式的概念

河内塔的目的是要将整个塔移动到另一根桩柱上,每次只能移动一个圆盘,且较大的圆盘 在移动过程中不能放置在较小的圆盘上面。现在要做的是求这个问题的最优解,既要完成这项任务移动多少次才是必须且足够的?
我们先推广到一般情况:考虑有 n 个圆盘 的情形。这样推广的一个好处是,我们可以大大简化问题。
定义:
- 设 Tn 表示根据卢卡斯规则,将 n 个圆盘从一根桩柱移动到另一根桩柱所需的最少移动次数。
则有:
- T0=0(没有圆盘,无需移动)
- T1=1
- T2=3
要移动三个圆盘时:
- 将上面的 2 个圆盘移到中间桩柱;
- 移动最底层的最大圆盘到目标桩柱;
- 再将那 2 个圆盘从中间桩柱移回最大圆盘之上。这一思路可推广至一般情况。
要移动 n 个圆盘(n>0):
- 将顶部的 n−1 个圆盘移动到辅助桩柱,需 Tn−1 次移动;
- 将最大的圆盘从起始桩柱移动到目标桩柱,需 1 次移动;
- 再将那 n−1 个圆盘从辅助桩柱移回目标桩柱,覆盖在最大圆盘上,又需 Tn−1 次移动。
综上有:
Tn≤2Tn−1+1,n>0
说明:此处使用不等号 "≤" 是因为该构造仅证明了 2Tn−1+1 次移动足够完成任务,但尚未证明这是最少所需次数。
现在我们需要证明是否存在更优的方法,答案是否定的:
任何解法都必须至少进行 2Tn−1+1 次移动。
原因:
- 我们最终必须移动最大的圆盘一次(从起始柱到目标柱)。
- 在首次移动最大圆盘之前,上面的 n−1 个较小圆盘必须全部移开,且只能集中在一根桩柱上(因为不能压住最大盘)。
- 将这 n−1 个圆盘移至辅助柱,至少需要 Tn−1 次移动。
- 在移动最大圆盘之后,若我们再次移动它(即不只一次),只会增加总步数,因此最优策略中最大圆盘仅移动一次。
[!NOTE]
为什么 n−1 个较小圆盘必须集中在一根桩柱上?
在河内塔问题中,当我们准备移动最大的圆盘(第 n 个圆盘)时,必须确保它上方没有任何其他圆盘。因此,其上的 n−1 个较小圆盘必须被全部移开。
然而,这些 n−1 个圆盘不能随意分散在两根桩柱上,而必须整体集中在一根桩柱上。原因如下:
虽然表面上看,我们可以把 n−1 个圆盘分成两组,分别放在 B 和 C 上,但实际上这会违反后续操作的可行性或最优性要求。
问题 1:空间资源极度有限
- 最大圆盘 Dn 仍在 A 上(尚未移动),所以 A 的顶部被占用,不能用于存放其他圆盘。
- 可用的只有 B 和 C 两根柱子来存放 n−1 个圆盘。
但如果我们将这 n−1 个圆盘分散存放(如一部分在 B,一部分在 C),就会导致:
没有足够的“中转柱”来完成后续重组。
因为要将两组独立的塔合并成一个有序塔,至少需要三根可用柱子(标准递归操作所需),但此时:
- C 上可能已有小圆盘,
- B 上也有,
- A 上还有最大盘 Dn,
缺少一根完全空闲的“辅助柱”,无法安全地进行合并操作。
问题 2:无法保证合法合并
假设我们把 n−1 个圆盘拆成两部分:
由于所有圆盘大小不同,且必须保持“大在下、小在上”的顺序,任何柱子上的堆叠都必须是合法塔。
但一旦拆分,这两个子塔之间没有包含关系(即一个不是另一个的前缀),就无法通过有限步数将它们合并为一个塔,除非借助第三根空柱 —— 而这根柱子很可能已被占用。
更严重的是:合并两个非连续子塔的操作本身可能比原问题更复杂,违背了“最小移动次数”的目标。
为了确保后续能顺利将所有小圆盘移回最大圆盘之上,我们必须:
- 将 n−1 个较小圆盘作为一个完整的塔,从 A 移动到某一根单一辅助柱(如 B);
- 此时 A 仅剩最大圆盘 Dn,C 完全空闲;
- 将 Dn 从 A 移动到 C;
- 再将那 n−1 个圆盘从 B 整体移动到 C,叠在 Dn 上。
这个过程依赖于递归结构:
移动 n 个圆盘 = 移动 n−1 个 → 移最大盘 → 再移动 n−1 个
而这一递归成立的前提是:n−1 个圆盘能作为一个整体被移动,这就要求它们始终集中在一根柱上。
- 在最后一次移动最大圆盘后,必须将那 n−1 个圆盘从辅助柱移回其上,这又至少需要 Tn−1 次移动。
因此,总的移动次数至少为:
Tn≥2Tn−1+1,n>0
此前我们已构造出一个策略,证明:
Tn≤2Tn−1+1,n>0
两者结合,得出等式成立:
Tn=2Tn−1+1,n>0(1.1)
像式 (1.1) 这样的一组等式被称为递归式(recurrence),也称为递推关系或递归关系:
它由两部分组成:
- 边界条件:T0=0,给出初始值;
- 递推方程:Tn=2Tn−1+1,说明如何用前面的值计算当前值。
严格来说,“递归式”需要边界值和递推关系共同构成。但有时人们也会把像 Tn=2Tn−1+1 这样的方程单独称为递归式,尽管它本身还不足以确定唯一解。
递归式是间接而低效的,虽然我们可以用递归式逐步暴力计算出任意 Tn,例如:但当 n 很大时(比如 n=64),这种逐层计算非常耗时。递归式提供的是局部规则,而不是全局图像。我们真正想要的是一个封闭形式(closed form):一个可以直接计算 Tn 的简洁表达式,无需依赖前面所有项。
1.1.2 递归式的求解
猜测形式
求解递归式的有效方法是:
- 猜测解的形式(通过小规模情形观察规律)
- 证明猜想正确(通常用数学归纳法)
我们列出前几项:
| n | Tn | 是否等于 2n−1? |
|---|
| 0 | 0 | 20−1=0 |
| 1 | 1 | 21−1=1 |
| 2 | 3 | 22−1=3 |
| 3 | 7 | 23−1=7 |
| 4 | 15 | 24−1=15 |
| 5 | 31 | 25−1=31 |
| 6 | 63 | 26−1=63 |
Tn=2n−1,n≥0(1.2)
这个公式对 n≤6 完全成立。
数学归纳
数学归纳法(mathematical induction)是一种证明某个命题对所有满足 n≥n0 的整数 n 都成立的通用方法。它包含两个关键步骤:
基础步骤(Basis)
验证命题在最小值 n=n0 时成立。
归纳步骤(Induction)
假设命题对所有从 n0 到 n−1 的整数都成立(称为归纳假设),然后证明它对 n 也成立。
这种方法的精妙之处在于:仅用有限步推理,就得到了无限多个结果。一旦基础和归纳都成立,命题对所有 n≥n0 自动成立。
证明过程
我们之前通过观察小情形猜出:
Tn=2n−1,n≥0(1.2)
现在用数学归纳法严格证明这个公式是正确的。
基础情形:n=0
根据递归式,T0=0。
而 20−1=1−1=0,所以:
T0=20−1
基础成立
归纳步骤:假设对 n−1 成立,证明对 n 成立
假设当 n≥1 时,归纳假设成立:
Tn−1=2n−1−1
根据递归式 (1.1):
Tn=2Tn−1+1
代入归纳假设:
Tn=2(2n−1−1)+1=2n−2+1=2n−1
因此,若公式对 n−1 成立,则对 n 也成立。
结论
由数学归纳法可知,对所有 n≥0,都有:
Tn=2n−1
1.1.3 求解有意义问题的三个阶段
河内塔问题展示了我们在面对复杂递推关系时的典型解决路径。这类问题的求解通常经历以下三个阶段:
(1) 研究小的情形
- 计算 T0,T1,T2,…
- 观察规律,建立直觉
- 为后续建模和验证提供依据
(2) 建立数学表达式(递归式)
-
引入记号 Tn
-
分析操作结构,建立递推关系:
Tn=2Tn−1+1,T0=0
-
这给出了精确但间接的描述
(3) 求解封闭形式并证明
- 猜测解的形式(如 Tn=2n−1)
- 用数学归纳法或其他方法证明其正确性
- 得到直接、高效、可扩展的表达式
这三个阶段构成了处理递推问题的标准范式:
观察 → 建模 → 求解 → 验证
1.2 平面上的直线
现在引入第二个问题,用一把比萨刀直直地切 n 刀,最多能得到多少块比萨饼?
更学术地表述为: **平面上 n 条直线最多能将平面划分成多少个区域?**记这个最大区域数为 Ln。
1.2.1 小情形分析
- 当 n=0(没有直线):整个平面是一个区域,故 L0=1;
- 当 n=1:一条直线将平面分成两部分,故 L1=2;
- 当 n=2:两条直线若相交,则可将平面分成 4 个区域,故 L2=4。

观察前几项,可能会得到一个错误的结论:我们可能会猜测:Ln=2n,因为当前每增加一条直线,区域数就加倍。遗憾的是,这是错误的。
要使区域数加倍,新增的第 n 条直线必须将每一个已有区域一分为二。 但这是不可能的。
关键在于:
每一个由直线围成的区域都是凸的。
[!NOTE]
在几何中,一个区域是凸的(convex),如果它满足以下条件:
对于该区域内的任意两个点,连接这两个点的整个线段也完全位于该区域内。
换句话说,区域内任意两点之间的直线段不会“穿出”该区域。
设 R 是平面上的一个区域。如果对任意两点 A,B∈R,都有:
线段 AB⊆R
则称 R 是一个凸区域。
凸区域的例子:
- 圆形(包括圆盘)
- 正方形、矩形、三角形(实心)
- 半平面(如 y>0)
- 任意两条直线相交形成的角域(无限延伸的部分)
非凸区域的例子:
- 月牙形
- 星形
- C 形或 U 形区域
- 多边形中有“凹角”的形状
而一条直线最多只能将一个凸区域分成两个部分。
因此,第 n 条直线能新增的区域数,等于它所穿过的已有区域的个数。
进一步分析:
- 它每穿过一个已有区域,就将其分裂为两个,从而增加一个新区;
- 它穿过的区域数,取决于它与之前直线的交点数。
具体地:
- 第 n 条直线最多能与前面的 n−1 条直线各交于一点;
- 由于两条直线至多交于一点,因此最多有 n−1 个不同的交点;
- 这些交点将第 n 条直线分成 n 段(包括射线和线段);
- 每一段穿过一个已有区域,从而新增一个区域。
因此,第 n 条直线最多能增加 n 个新区域。

如图所示,当加入第三条直线时,它最多穿过 3 个已有区域,从而最多增加 3 个新区。
已知 L2=4,所以:
L3=4+3=7
1.2.2 推导递归式
综上所述,我们得到:
-
第 n 条直线最多可增加 n 个区域;
-
因此:
Ln≤Ln−1+n,n>0
进一步,我们可以通过适当放置直线使等号成立:
- 让第 n 条直线不与任何已有直线平行(保证相交);
- 且不经过任何已有的交点(保证所有交点互异);
这样,它将与前 n−1 条直线在 n−1 个不同点相交,被分成 n 段,穿过 n 个区域,从而恰好增加 n 个新区。
因此,上界是可以达到的,递归式为:
Ln=Ln−1+n,n>0(1.4)
1.2.3 封闭形式求解
将递归式反复代入:
Ln=Ln−1+n=(Ln−2+(n−1))+n=Ln−2+(n−1)+n=(Ln−3+(n−2))+(n−1)+n=Ln−3+(n−2)+(n−1)+n⋮=L0+1+2+3+⋯+(n−2)+(n−1)+n=1+Sn
其中 Sn 表示前 n 个正整数的和:
Sn=1+2+3+⋯+n
所以:
Ln=1+Sn(1.5)
即:Ln 比前 n 个自然数之和 Sn 大 1。
使用高斯求和法求 Sn :
SnSn2Sn===1n(n+1)+++2(n−1)(n+1)+++⋯⋯⋯+++n1(n+1)
右边共有 n 项,每项都是 n+1,因此:
2Sn=n(n+1)⇒Sn=2n(n+1),n≥0(1.5)
代入 Ln=1+Sn 得:
Ln=2n(n+1)+1,n≥0(1.6)
这就是我们所求的封闭形式解。
封闭形式的含义
什么是“封闭形式”?通常指:
一个表达式,可以用固定次数(与 n 无关)的“标准运算”(如加、减、乘、除、幂、阶乘等)来计算 f(n),而不需要递归或无限过程。
例如:
- 2n−1 是封闭形式
- 2n(n+1)+1 是封闭形式
- 1+2+⋯+n 不是封闭形式 (依赖“…”)
- Tn=2Tn−1+1 不是封闭形式 (递归定义)
有时,某些运算因频繁出现而被“升级”为基本运算。例如:
- n!=1×2×⋯×n 原本不是封闭形式;
- 但由于阶乘极其重要,现在 n! 被视为封闭形式。
1.2.4 推广:折线划分区域
考虑一个变形问题:
用 n 条带锯齿的折线(每条折线由两条射线通过一个拐点连接而成)代替直线,最多能划分多少区域?记为 Zn。
观察发现:
- 一条折线类似于两条直线,但其两臂不经过交点延伸,导致部分区域合并;
- 每条折线比两条直线少产生 2 个区域。
因此:
Zn=L2n−2n
代入 L2n=22n(2n+1)+1=2n2+n+1,得:
Zn=(2n2+n+1)−2n=2n2−n+1,n≥0(1.7)
当 n 很大时,主导项决定增长趋势:
Ln∼21n2,Zn∼2n2
所以:
LnZn→4(n→∞)
即:用折线划分的区域数大约是直线的四倍。
注:符号 ∼ 表示“渐近等价”,将在后续章节中正式定义。
1.3 约瑟夫问题
约瑟夫问题既:n 个人围成一圈,编号为 1 到 n,从第 1 人开始,每隔一人淘汰一人(即每次淘汰第 2 个、第 4 个……),直到只剩一人。求最后幸存者的编号,记为 J(n)。
1.3.1 小情形分析
以 n=10 为例:

淘汰顺序为:2, 4, 6, 8, 10, 3, 7, 1, 9
最终幸存者是 5,因此:
计算更多小值:
| n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|
| J(n) | 1 | 1 | 3 | 1 | 3 | 5 | 7 | 1 |
观察发现:
- J(n) 总是奇数;
- 当 n 是 2 的幂时(如 n=1,2,4,8),有 J(n)=1;
- 数值呈现某种周期性增长趋势。
1.3.2 推导递归式
情形一:n=2k(偶数)
假设有 2n 个人围成一圈:

第一轮会淘汰所有偶数编号的人(2, 4, 6, ..., 2n),剩下的是奇数编号:1, 3, 5, ..., 2n−1。
这 n 个人重新构成一个类似的约瑟夫问题,只是编号不同。
关键观察:
剩下的这些人可以重新编号为 1 到 n,其中:
- 原编号 2k−1 对应新编号 k
如果在 n 人的约瑟夫问题中幸存者编号为 J(n),那么在原始问题中对应的编号是:
原编号=2J(n)−1
因此:
J(2n)=2J(n)−1,n≥1(1.8a)
情形二:n=2k+1(奇数)
考虑 2n+1 个人。第一轮淘汰顺序为:2, 4, 6, ..., 2n,然后轮到第 1 人(因为下一个是 2n+2,超出范围,回到 1)。
所以第 1 人也被淘汰,剩下的是:3, 5, 7, ..., 2n+1,共 n 人。
这些人的编号是:2k+1,其中 k=1,2,…,n
如果在 n 人的子问题中幸存者编号为 J(n),则对应原编号为:
原编号=2J(n)+1
因此:
J(2n+1)=2J(n)+1,n≥1(1.8b)
完整递归式
结合基础情形 J(1)=1,我们得到完整的递归定义:
J(2n)=2J(n)−1,n≥1;
J(2n+1)=2J(n)+1,n≥1.(1.8)
这个递归式的优点是:每次递归都将问题规模减半,因此即使对很大的 n(如 n=106),也只需约 log2n 次计算即可求出 J(n)。
1.3.3 封闭形式求解
猜想
虽然递归式高效,但我们仍希望得到一个封闭形式的表达式。
观察前几项:
| n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|
| J(n) | 1 | 1 | 3 | 1 | 3 | 5 | 7 | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 1 |
发现规律:
- 每当 n 是 2m 时,J(n)=1;
- 在 2m 和 2m+1 之间,J(n) 从 1 开始,每次增加 2。
因此,我们将 n 写成:
n=2m+l,其中 m≥0, 0≤l<2m
这里 2m 是不超过 n 的最大 2 的幂,l=n−2m。
观察可得:
J(2m+l)=2l+1,m≥0, 0≤l<2m(1.9)
证明
要证约瑟夫函数 J(n) 的封闭形式猜想:
J(2m+l)=2l+1,其中 m≥0, 0≤l<2m(1.9)
数学归纳法(对 m 归纳)
基础情形:当 m=0 时,n=20+l=1+l,而 l<20=1,故 l=0,n=1。
此时 J(1)=1,且 2l+1=1,成立。
归纳假设:假设对所有小于 m 的情形,公式 (1.9) 成立。
归纳步骤:
分两种情况讨论:
-
若 n=2m+l 是偶数,即 l 为偶数。
设 n=2k,则:
J(2m+l)=J(2k)=2J(k)−1
其中 k=2m−1+l/2。
由归纳假设:
J(k)=2(l/2)+1=l+1
所以:
J(2m+l)=2(l+1)−1=2l+1
-
若 n=2m+l 是奇数,即 l 为奇数。
设 n=2k+1,类似可得:
J(2m+l)=J(2k+1)=2J(k)+1
同样代入归纳假设可得结果为 2l+1。
综上,公式 (1.9) 对所有 m≥0 成立。
1.3.4 二进制视角
一个更简洁的理解方式是使用二进制表示。
设 n 的二进制表示为:
n=(bmbm−1⋯b1b0)2,bm=1
则:
J(n)=(bm−1bm−2⋯b0bm)2(1.10)
[!NOTE]
在二进制运算中,左循环移位(Left Circular Shift)是一种特殊的位操作。它的规则是:
- 将一个数的二进制表示中的所有位向左移动一位;
- 原来最左边的那一位(最高位)不丢弃,而是“循环”到最右边,成为最低位。
这与普通的左移操作不同:普通左移会将最高位“丢掉”,并在右边补0;而循环左移是“首尾相连”的。
举例说明
以 n=13 为例:
- 13 的二进制表示是:(1101)2
- 将其所有位向左移动一位,最后会得到(1011)2=(11)10
过程如下:
即:将 n 的二进制表示向左循环移动一位,得到 J(n)。
示例:n=100
- 100=(1100100)2
- 左循环移位:(1001001)2=64+8+1=73
- 所以 J(100)=73
这与公式 (1.9) 一致:
100=64+36=26+36,故 J(100)=2×36+1=73。
迭代约瑟夫函数
如果我们反复应用 J 函数,相当于不断对二进制数进行左循环移位。
由于每次移位后若最高位为 0,则该位消失,数值不会增加,最终会进入一个不动点,即 J(k)=k。
[!NOTE]
在约瑟夫问题中,当我们反复应用函数 J(即不断计算 J(J(J(…J(n)…)))),会得到一个递减的整数序列。这个序列最终会停止变化,进入一个不动点(fixed point),即某个满足 J(k)=k 的数 k。
一个数 k 被称为函数 J 的不动点,如果:
以 n=13 为例:
- 13=(1101)2
- J(13)=J((1101)2)=(1011)2=11
- J(11)=J((1011)2)=(0111)2=(111)2=7
- J(7)=J((111)2)=(111)2=7
从 J(7) 开始,值不再变化。因此:
J(J(J(13)))=7,且 J(7)=7
最终进入不动点 k=7。
观察发现,所有不动点的二进制表示都由连续的 1 组成:
| k | 二进制 | J(k) |
|---|
| 1 | 1 | 1 |
| 3 | 11 | 11 |
| 7 | 111 | 111 |
| 15 | 1111 | 1111 |
这是因为:
- 对于 k=(111⋯1)2,其二进制长度为 m,则 k=2m−1;
- 将其循环左移一位,仍然是 (111⋯1)2,因为所有位都相同;
- 所以 J(k)=k。
因此,所有形如 2m−1 的数都是不动点。
迭代最终会进入不动点的关键原因在于:
在循环左移过程中,一旦最高位变为 0,它就会在下一次移位时被“丢弃”。
让我们以 n=13=(1101)2 为例,追踪其迭代过程:
-
n=13=(1101)2
→ J(13)=(1011)2=11
(最高位 1 移到末尾)
-
n=11=(1011)2
→ J(11)=(0111)2=(111)2=7
(注意:(0111)_2 实际上是 111,前导零被忽略)
-
n=7=(111)2
→ J(7)=(111)2=7
(全为 1,循环移位不变)
从第 2 步开始,数值从 4 位变为 3 位,因为最高位是 0,被自动截断。
这个过程持续进行,直到所有“0”都被移出,只剩下“1”。
不动点的值由 1 的个数决定
设 n 的二进制表示中有 ν(n) 个 1。例如:
- 13=(1101)2,有 3 个 1 → ν(13)=3
- 100=(1100100)2,有 3 个 1 → ν(100)=3
那么,经过足够多次的 J 迭代后,最终的不动点是:
k→∞limJ(k)(n)=2ν(n)−1
示例
- n=13, ν(13)=3 → 极限为 23−1=7 ✅
- n=100, ν(100)=3 → 极限为 7
- n=(10110110110111)2,有 10 个 1 → 极限为 210−1=1023
这个不动点是:**一个全由 1 组成的二进制数,其长度等于 n 的二进制表示中 1 的个数 ∗∗ν(n)。
因此:
k→∞limJ(k)(n)=2ν(n)−1
示例
- n=13=(1101)2,ν(13)=3,故极限为 23−1=7
- n=(10110110110111)2,有 10 个 1,故极限为 210−1=1023
1.3.5 特殊情形
特殊情形: J(n)=n/2J(n)=n/2?
我们曾猜测当 n 为偶数时 J(n)=n/2J(n)=n/2,虽然不普遍成立,但存在无穷多个解。
设 n=2m+l,要求:
J(n)=2l+1=2n=22m+l
解得:
l=31(2m−2)
当 m 为奇数时,2m−2 是 3 的倍数,l 为整数,且 l<2m,故有解。
| m | n=2m+l | J(n) | n(二进制) |
|---|
| 3 | 10 | 5 | 1010 |
| 5 | 42 | 21 | 101010 |
| 7 | 170 | 85 | 10101010 |
这些数的二进制形式呈现“10”重复模式,左循环移位等价于数值减半。
1.3.6 推广
一般化递推式
回顾上文优:
约瑟夫问题递归式为:
J(1)J(2n)J(2n+1)=1=2J(n)−1,n≥1=2J(n)+1,n≥1(1.8)
其封闭形式解:
J(2m+l)=2l+1,其中 0≤l<2m(1.9)
从二进制视角观察,我们发现:
J((bmbm−1⋯b0)2)=(bm−1⋯b0bm)2(1.10)
即:J(n) 等于 n 的二进制表示向左循环移动一位的结果。
考虑更一般的递归式:
f(1)=α;
f(2n)=2f(n)+β,n≥1;
f(2n+1)=2f(n)+γ,n≥1.(1.11)
原约瑟夫问题对应 α=1,β=−1,γ=1。
我们猜测解具有线性结构:
f(n)=A(n)α+B(n)β+C(n)γ(1.13)
通过后续可证明其中:
- A(n)=2m,n=2m+l
- B(n)=2m−1−l
- C(n)=l
[!NOTE]
成套方法(Repertoire Method)是一种求解参数化递归式(如线性递推关系)的系统性技巧。其核心思想是:
不直接求解复杂的通解,而是通过构造一组“已知答案”的特例,反向推导出通解的结构。
具体来说,我们考虑一个包含未知参数的通用递归式。该递归式实际上定义了一族函数,每个参数组合对应一个具体的函数。成套方法通过以下步骤求解:
- 选取特例:选择几个形式简单、我们已知其解的函数(如常数函数、恒等函数等)。
- 反推参数:将这些已知解代入通用递归式,反向求解出它们所对应的参数值。
- 建立方程:利用“解是参数的线性函数”这一假设,将已知解与参数的关系转化为关于通解中未知函数的方程。
- 求解系统:联立多个方程,解出通解的结构。
为验证 (1.13),我们使用成套方法:通过选取特殊函数反推参数。
我们假设存在某个参数组合 (α,β,γ),使得递归式 (1.11) 的解是常数函数 f(n)=1。
将 f(n)=1 代入递归式:
- f(1)=1⇒α=1
- f(2n)=1,而右边是 2f(n)+β=2⋅1+β,所以 1=2+β⇒β=−1
- f(2n+1)=1,而右边是 2f(n)+γ=2+γ,所以 1=2+γ⇒γ=−1
因此,当参数为 (α,β,γ)=(1,−1,−1) 时,解是 f(n)=1。
现在,将这个结果代入我们猜测的通解形式 (1.13):
f(n)=A(n)⋅1+B(n)⋅(−1)+C(n)⋅(−1)=A(n)−B(n)−C(n)
但我们知道 f(n)=1,所以:
A(n)−B(n)−C(n)=1(Eq. 1)
这是关于 A(n),B(n),C(n) 的第一个方程。
再假设存在某个参数组合,使得解是恒等函数 f(n)=n。
代入递归式:
- f(1)=1⇒α=1
- f(2n)=2n,而右边是 2f(n)+β=2n+β,所以 2n=2n+β⇒β=0
- f(2n+1)=2n+1,而右边是 2f(n)+γ=2n+γ,所以 2n+1=2n+γ⇒γ=1
因此,当参数为 (α,β,γ)=(1,0,1) 时,解是 f(n)=n。
代入通解形式 (1.13):
f(n)=A(n)⋅1+B(n)⋅0+C(n)⋅1=A(n)+C(n)
而 f(n)=n,所以:
A(n)+C(n)=n(Eq. 2)
这是第二个方程。
选择 f(n) 为不超过 n 的最大2的幂,即 f(n)=2m。
代入递归式:
- f(1)=1⇒α=1
- 对于 f(2n):2n 的最大2的幂是 2k,n 的最大2的幂是 2k−1,所以 f(2n)=2⋅f(n),因此 β=0
- 对于 f(2n+1):2n+1 是奇数,其最大2的幂仍为 2k,而 f(n)=2k−1,所以 f(2n+1)=2⋅f(n),因此 γ=0
因此,当参数为 (α,β,γ)=(1,0,0) 时,解是 f(n)=2m。
代入通解形式 (1.13):
f(n)=A(n)⋅1+B(n)⋅0+C(n)⋅0=A(n)
而 f(n)=2m,所以:
A(n)=2m(Eq. 3)
这是第三个方程。
现在有三个方程:
- A(n)−B(n)−C(n)=1
- A(n)+C(n)=n
- A(n)=2m
其中 n=2m+l,0≤l<2m。
我们来解这个方程组。
从 (Eq. 3) 得:A(n)=2m
代入 (Eq. 2):
2m+C(n)=n⇒C(n)=n−2m=l
代入 (Eq. 1):
2m−B(n)−l=1⇒B(n)=2m−l−1
至此,我们求出了通解中所有未知函数的表达式:
- A(n)=2m
- B(n)=2m−1−l
- C(n)=l
因此,对于任意参数 α,β,γ,递归式 (1.11) 的解为:
f(n)=2mα+(2m−1−l)β+lγ
二进制推广解
二进制展开
在约瑟夫问题的分析中,J(n) 等于 n 的二进制表示向左循环移动一位的结果。。
我们已知约瑟夫函数的封闭形式为:
J(2m+l)=2l+1,其中 0≤l<2m(1.9)
设 n 的二进制表示为:
n=(bmbm−1⋯b1b0)2,bm=1
则 l=(0bm−1⋯b0)2。
计算 J(n)=2l+1:
- 2l 相当于将 l 的二进制左移一位,得到 (bm−1⋯b00)2;
- 2l+1 相当于在末尾加 1,得到 (bm−1⋯b01)2;
- 而 bm=1,所以 J(n)=(bm−1⋯b0bm)2。
因此,我们得出:
J((bmbm−1⋯b0)2)=(bm−1⋯b0bm)2(1.10)
这正是“左循环移位”的数学表达。
我们考虑更一般的递归式:
f(1)=α;
f(2n)=2f(n)+β,n≥1;
f(2n+1)=2f(n)+γ,n≥1.(1.11)
可以将其统一写为:
f(2n+j)=2f(n)+βj,j=0,1(1.15)
其中 β0=β,β1=γ。
现在,我们对 f(n) 进行递归展开。设 n=(bmbm−1⋯b0)2,则:
f((bmbm−1⋯b0)2)=2f((bmbm−1⋯b1)2)+βb0=2[2f((bmbm−1⋯b2)2)+βb1]+βb0=4f((bmbm−1⋯b2)2)+2βb1+βb0=8f((bmbm−1⋯b3)2)+4βb2+2βb1+βb0⋮=2mf((bm)2)+k=0∑m−12kβbk=2mα+2m−1βbm−1+⋯+2βb1+βb0
这个表达式揭示了 f(n) 的结构:它是一个关于 α 和 βj 的线性组合,其系数由 n 的二进制位决定。
位映射
观察最后的表达式:
f((bmbm−1⋯b0)2)=2mα+2m−1βbm−1+⋯+2βb1+βb0
我们可以将这个求和式理解为一个新数字的值,这个新数字的“数字”由 α 和 βj 构成。
具体规则是:
- 位映射:将 n 的二进制表示 (bmbm−1⋯b0)2 中的每一位进行映射:
- 最高位 bm 映射为 α。
- 其余位 bk (k<m) 映射为 βbk(即如果 bk=0,映射为 β;如果 bk=1,映射为 γ)。
- 构成新序列:得到一个由 α 和 βj 构成的新序列:(α,βbm−1,βbm−2,…,βb0)。
- 按权值求和:将这个序列的第 i 个元素(从左到右,索引从0开始)乘以 2m−i,然后求和。
这个过程等价于将新序列视为一个以2为基数的数字,并计算其数值。
即:
f((bmbm−1⋯b0)2)=(α βbm−1 βbm−2 ⋯ βb0)2(1.16)
这里的下标 2 不表示十进制,而是强调我们是按照二进制的权值体系(2k)来计算这个由符号构成的“数字”的值。
-
这不是一个真正的进制数:α,β,γ 是任意常数,它们本身不是数字。
-
这是一种记号:(α βbm−1 ⋯ βb0)2 是一个紧凑的记号,它代表了求和公式:
数值=α⋅2m+βbm−1⋅2m−1+⋯+βb0⋅20
计算 f(100):
-
将 n=100 写成二进制:100=(1100100)2
- b6=1,b5=1,b4=0,b3=0,b2=1,b1=0,b0=0
-
应用位映射规则:
- 最高位 b6=1 → α=1
- b5=1 → β1=γ=1
- b4=0 → β0=β=−1
- b3=0 → β0=−1
- b2=1 → β1=1
- b1=0 → β0=−1
- b0=0 → β0=−1
-
得到映射序列:(1, 1, −1, −1, 1, −1, −1)
-
按二进制求值:
f(100)=1⋅26+1⋅25+(−1)⋅24+(−1)⋅23+1⋅22+(−1)⋅21+(−1)⋅20=64+32−16−8+4−2−1=73
这与我们之前通过 J(100)=2×36+1=73 计算的结果完全一致。
变基数递归式
假设当前我们有一个递归式f(n) 遵循以下规则:
-
基础规则:
- f(1)=34
- f(2)=5
-
递归规则(对于任何 n≥1):
- f(3n)=10×f(n)+76 (规则 A)
- f(3n+1)=10×f(n)−2 (规则 B)
- f(3n+2)=10×f(n)+8 (规则 C)
任务是:计算 f(19)。
这些规则告诉我们,如何从一个较小的 f(n) 推出一个较大的 f(某个数)。
例如,我知道 f(1)=34,那么:
- 用规则 A:f(3×1)=f(3)=10×f(1)+76=10×34+76=416
- 用规则 B:f(3×1+1)=f(4)=10×f(1)−2=10×34−2=338
- 用规则 C:f(3×1+2)=f(5)=10×f(1)+8=10×34+8=348
类似地,我知道 f(2)=5,那么:
- f(6)=f(3×2)=10×f(2)+76=10×5+76=126
- f(7)=f(3×2+1)=10×f(2)−2=10×5−2=48
- f(8)=f(3×2+2)=10×f(2)+8=10×5+8=58
19 不能被 3 整除,所以看它除以 3 的余数:
- 19÷3=6 余 1,所以 19=3×6+1
这符合规则 B:f(3n+1)=10×f(n)−2
所以:
f(19)=f(3×6+1)=10×f(6)−2
我们现在需要 f(6)。而 6=3×2+0,符合规则 A:
f(6)=f(3×2)=10×f(2)+76=10×5+76=126
代回:
f(19)=10×126−2=1260−2=1258
所以,f(19)=1258。
我们刚才的计算是“一步一步推”的。现在,我们换一个视角,看看能不能找到一个更快、更直接的方法。
观察输入 n=19
-
把 19 写成 3进制(因为递归规则是以 3n+j 的形式出现的):
- 19÷3=6 余 1
- 6÷3=2 余 0
- 2÷3=0 余 2
- 所以 19=(201)3
这意味着:19=2×32+0×31+1×30
观察输出 f(19)=1258
- 把 1258 写成 10进制:
- 1258=1×103+2×102+5×101+8×100
建立映射关系
现在,我们把输入 19=(201)3 的每一位,和计算过程联系起来:
- 最高位
2:这对应着我们从 f(2) 开始计算。而 f(2)=5。
- 中间位
0:这对应着规则 A(因为 3n+0),其常数是 +76。
- 最低位
1:这对应着规则 B(因为 3n+1),其常数是 −2。
在计算中,我们是这样做的:
f(19)=10×(10×f(2)+76)−2
我们来拆解这个式子:
- 最内层:f(2)=5
- 然后:10×5+76=126 (这对应中间位
0)
- 最后:10×126−2=1258 (这对应最低位
1)
注意,5、76、-2 这三个数,恰好就是我们从“最高位”、“中间位”、“最低位”提取出来的“映射值”。
变基数的本质
我们把这三个“映射值”按顺序写出来:5, 76, -2
然后,我们把它们像一个10进制数一样“拼”起来:
- 5×102+76×101+(−2)×100=500+760−2=1258
通用方法
现在,我们终于可以给出一个清晰的、可操作的步骤:
要计算一个形如以下形式的递归式:
- f(dn+j)=c×f(n)+βj
- f(1)=α1,f(2)=α2,…,f(d−1)=αd−1
计算 f(n) 的步骤是:
- 分解:把 n 写成 d 进制。
- 映射:
- 把 d 进制数的第一位(最高位) k 映射为 αk。
- 把其余每一位 j 映射为 βj。
- 重组:把映射得到的这一串数,视为一个 c 进制 的数,计算其十进制值。
应用到我们的例子
- d=3, c=10
- n=19=(201)3
- 映射:
- 第一位
2 → α2=f(2)=5
- 第二位
0 → β0=76
- 第三位
1 → β1=−2
- 重组:(5,76,−2) 作为一个 10 进制数:5×100+76×10+(−2)×1=1258
为什么叫“变基数”?
因为它改变了数字的“解读方式”:
- 输入 n 是用 d 进制 来“读”的(这里是3进制)。
- 输出 f(n) 是用 c 进制 来“算”的(这里是10进制)。
整个过程就像一个“翻译器”,把一个 d 进制的“消息”翻译成一个 c 进制的“答案”。