《具体数学》学习笔记: 1.递归问题
序言:
本系列将记录《具体数学》中学习的重要内容。第一章,递归问题中探讨了三个范例。
1.1 汉诺塔(The Tower of Hanoi)
问题描述:给定三个桩柱,标记为
a
,
b
,
c
a, b, c
a,b,c。另有
n
n
n 个圆盘,这些圆盘以大小递减的方式套在桩柱
a
a
a 上。 目标使得要将全部圆盘移动到另一根桩柱
b
b
b 上,每次只能移动一个圆盘,且较大的圆盘在移动过程中不能放置在较小的圆盘上面。
递归思路:对于 n n n 个圆盘,我们首先要将 n − 1 n - 1 n−1 个圆盘移动到辅助桩柱 c c c 上,然后将最后一个圆盘从 a a a 移动到桩柱 b b b 上,再把 c c c 上的 n − 1 n - 1 n−1 个桩柱移动到 b b b 上。
我们用
T
n
T_n
Tn 表示移动
n
n
n 个圆盘的总花费
c
o
s
t
cost
cost, 则
T
n
=
2
T
n
−
1
+
1
T
0
=
0
,
T
1
=
1
T_n = 2T_{n-1} + 1\\ T_0 = 0, T_1 = 1
Tn=2Tn−1+1T0=0,T1=1
利用数学归纳法或者配置等比数列,可以得到
T
n
=
2
n
−
1
,
n
≥
0
T_n = 2^n - 1, \quad n\ge0
Tn=2n−1,n≥0
- C++实现
void hanio(int n, char a, char b, char c) {
if (n == 1) cout << a << " -> " << b << endl;
else {
hanio(n - 1, a, c, b);
cout << a << " -> " << b << endl;
hanio(n - 1, c, b, a);
}
}
int main() {
hanio(5, 'a', 'b', 'c');
return 0;
}
1.2 平面上的直线(Lines in The Plane)
问题描述:平面上
n
n
n 条直线所界定的区域的最大个数
L
n
L_n
Ln 是多少?
递归思路:从前3项来看,似乎
L
n
=
2
n
L_n=2^n
Ln=2n, 但是显然
L
3
=
7
L_3=7
L3=7是不符合猜想的。换一种思路,
L
n
L_{n}
Ln 是在
L
n
−
1
L_{n - 1}
Ln−1 的基础上增加一条直线,而新的直线能与之前
n
−
1
n - 1
n−1条直线形成
n
−
1
n - 1
n−1 个交点,并形成
n
−
1
+
1
=
n
n - 1 + 1 = n
n−1+1=n 个新的区域,即
L
n
=
L
n
−
1
+
n
L
0
=
1
,
L
1
=
2
L_n = L_{n-1} + n\\ L_0 = 1, L_1 = 2
Ln=Ln−1+nL0=1,L1=2
可以解出
L
n
=
(
L
0
+
∑
k
=
1
n
k
)
=
1
+
n
(
n
+
1
)
2
L_n = (L_0 + \sum_{k = 1}^{n}{k}) = 1 + \frac{n(n+1)}{2}
Ln=(L0+∑k=1nk)=1+2n(n+1).
另外,本书中还提到一种扩展形式:将直线改成折线,具体如下示
我们可以把折线与两条直线相比较,如果用折线代替两条直线,我们会“损失” 2 个区域(本来是4个, 现在只有2个)
因此这种情况下,
Z
n
=
L
2
n
−
2
n
=
2
n
2
−
n
+
1
Z_n = L_{2n} - 2n = 2n^2 - n + 1
Zn=L2n−2n=2n2−n+1.
1.3 约瑟夫问题(The Josephus Problem)
问题描述:
n
n
n 个人围成一个圆圈,分别从 1 标记到
n
n
n。从1号位开始,每隔 1 个人删去 1 个人,直到圆圈中只剩下一个人,例如
n
=
10
n = 10
n=10 的情形:消去的顺序是2, 4, 6, 8, 10, 3, 7, 1, 9, 于是 5 幸存下来。我们需要求解幸存者的号码
J
(
n
)
J(n)
J(n).
递归式(分析比较复杂, 这里直接记住):
J
(
1
)
=
1
;
J
(
2
n
)
=
2
J
(
n
)
−
1
,
n
≥
1
;
J
(
2
n
+
1
)
=
2
J
(
n
)
+
1
,
n
≥
1
;
\begin{aligned} &J(1) = 1;\\ &J(2n) = 2J(n) - 1, &\quad n \ge 1;\\ &J(2n + 1) = 2J(n) + 1, &\quad n \ge 1;\\ \end{aligned}
J(1)=1;J(2n)=2J(n)−1,J(2n+1)=2J(n)+1,n≥1;n≥1;
解为:
J
(
(
b
m
b
m
−
1
.
.
.
b
1
b
0
)
2
)
=
(
b
m
−
1
.
.
.
b
0
b
1
b
m
)
2
J((b_mb_{m-1}...b_1b_0)_2) = (b_{m-1}...b_0b_1b_m)_2
J((bmbm−1...b1b0)2)=(bm−1...b0b1bm)2
即,在
n
n
n 的二进制下,向左循环移动1位便可以得到
J
(
n
)
J(n)
J(n).
- 拓展
对于形如
f
(
j
)
=
α
j
,
1
≤
j
<
d
;
f
(
d
n
+
j
)
=
c
f
(
n
)
+
β
j
,
0
≤
j
<
d
,
n
≥
1
;
\begin{aligned} &f(j) = \alpha_j, \quad &1 \le j < d;\\ &f(dn + j) = cf(n) + \beta_j, \quad &0 \le j < d,\ n \ge1; \end{aligned}
f(j)=αj,f(dn+j)=cf(n)+βj,1≤j<d;0≤j<d, n≥1;
的递归式,他有变动基数的解
f
(
(
b
m
b
m
−
1
.
.
.
b
1
b
0
)
d
)
=
(
α
b
m
β
b
m
−
1
β
b
m
−
2
.
.
.
β
b
1
β
b
0
)
c
f((b_mb_{m-1}...b_1b_0)_d) = (\alpha_{b_m}\beta_{b_{m-1}}\beta_{b_{m-2}}...\beta_{b_{1}}\beta_{b_{0}})_c
f((bmbm−1...b1b0)d)=(αbmβbm−1βbm−2...βb1βb0)c
即,我们需要将
d
d
d 进制下的
n
n
n 按照相应的变换规则,转换成
c
c
c 进制,便是所求解。其中,首项遵循边界式
(
α
)
(\alpha)
(α),其余项遵循递归式
(
β
)
(\beta)
(β)。
例如,给定递归式
f
(
1
)
=
34
;
f
(
2
)
=
5
;
f
(
3
n
)
=
10
f
(
n
)
+
76
,
n
≥
1
;
f
(
3
n
+
1
)
=
10
f
(
n
)
−
2
,
n
≥
1
;
f
(
3
n
+
2
)
=
10
f
(
n
)
+
8
,
n
≥
1
;
\begin{aligned} f(1) &= 34;\\ f(2) &= 5;\\ f(3n) &= 10f(n) + 76, &\quad n \ge 1;\\ f(3n + 1) &= 10f(n) - 2, &\quad n \ge 1;\\ f(3n + 2) &= 10f(n) + 8, &\quad n \ge 1; \end{aligned}
f(1)f(2)f(3n)f(3n+1)f(3n+2)=34;=5;=10f(n)+76,=10f(n)−2,=10f(n)+8,n≥1;n≥1;n≥1;
若求解
f
(
19
)
f(19)
f(19),根据上述理论,我们需要将 19 的 3 进制
(
201
)
3
(2 0 1)_3
(201)3转换成 10 进制:
- 2 → 5 2 \to 5 2→5
- 0 → 76 0 \to 76 0→76
- 1 → − 2 1 \to -2 1→−2
因此, f ( 19 ) = ( 5 76 − 2 ) 10 = 1258 f(19) = (5\ \ 76\ -2)_{10} = 1258 f(19)=(5 76 −2)10=1258.