递归是我们经常要用到的算法,理由是方便,但是递归是要付出代价的,所以有时候我们必须把递归的解变成封闭式的解,下面将是一些关于求递归的解的问题以及求递归的封闭式的解的方法。
一、概念介绍
首先,介绍一下递归式的定义:
1)边界值T0;
2)用前面的值给出一般值的方程。
例子:T0 = 0 ;
Tn = 2Tn-1 + 1,n>0 ;
然后,要用到数学归纳法,因此在这里介绍一下:
数学归纳法用途:证明某个命题对所有满足n>=n0的整数n都成立;
步骤:基础->证明n=n0时,该命题正确;
归纳->假设n>n0时,该命题对[n0,n-1]范围内的所有值都成立;
再证明该命题对n成立;
最后,是封闭式:
如果可以利用至多固定次数(其次数与n无关)的“人人熟知”标准运算来计算量F(n)的表达式,那么这个表达式是封闭的。
由此可知,平时见到的一般表达式是封闭式,但像递归式这样,计算次数和n有关的则不是封闭式。
二、一般解法
步骤:1)研究小的,基础的情形;
2)对有意义的量求出数学表达式并给出证明(递归式);
3)对数学表达式求出封闭式并予以证明。
三、例子
1)河内塔
问题描述:
现有3根柱子A、B、C,A上有n个大小不重复的圆盘,且大盘永远再小盘下面,问把A柱子上所有的盘子移到C柱子上,且不能违反小盘压大盘的原则,每次只能移动一个圆盘,至少要移动多少次?
- 研究小的,基础的情形
设Tn是移动n个盘子从A到C所需要的最少次数
T0 = 0; T1 = 1; T2 = 3; - 求出递归式
我们这样来考虑,要移动n个盘子到C柱子,则要移动上面n-1个盘子到B柱子,再把第n个盘子移动到C柱子,最后把B柱子上的n-1个盘子移动到C柱子上,这样得到如下递归式:
T0 = 0; Tn = 2Tn-1 + 1,n>0; - 求封闭式
法一:猜出正确解,然后用数学归纳法证明
T0 = 0 = 2^0 - 1; T1 = 1 = 2^1 - 1; T2 = 3 = 2^2 - 1; T3 = 7 = 2^3 - 1;
看起来是Tn = 2^n - 1, n>=0; 起码对于n<=3是成立的
证明:基础显然是正确的,Tn = 2Tn-1 + 1 = 2(2^(n-1) -1) + 1 = 2^n - 1;
法二:稍微利用一下你的洞察力,或者想一下高中的求和式的各种方法,得出如下式子:
T0 + 1 = 1; Tn + 1 = 2(Tn-1 + 1), n>0;
令Sn = Tn + 1, 换元,有:
S0 = 1; Sn = 2Sn-1, n>0;
到了这里,上过高中的你,肯定很快得出Sn = 2^n,从而有Tn = 2^n -1;
2)平面上的直线
问题描述:
原题是:用一把比萨刀直直地切n刀,可以得到多少块比萨?
换一下概念就是:平面上n条直线所界定的区域的最大个数Ln是多少?
- 研究小的、基础的情况
当n=0时,L0 = 1;当n=1时,L1 = 2;当n=2时,L2 = 4;当n=3时,L3 = 7; - 求出递归式
我们知道,对已有的n-1条直线,一条直线与之相交至多有n-1个交点,也就是至多在原有区域的基础上再切割出n个区域(参考n-1条平行线划分n个区域,多加一条直线与之相交,会多分割n个区域)。由此得出以下递归式:
L0 = 1;Ln = Ln-1 + n,n>0; - 求出封闭式
使用累加法:Ln = Ln-1 + n
Ln-1 = Ln-2 + n-1
...
L1 = L0 + 1
L0 = 1 累加得Ln = 1 + (1 + 2 + ... + n) = n(n+1)/2 + 1,n>=0;
为了严谨,用数学归纳法证明一下,关键步骤为:Ln = Ln-1 + n = ((n-1)n/2 + 1) + n = n(n+1)/2 + 1;
3)平面上的折线
问题描述:不错,这是平面上的直线的变形,只是用折线代替直线,设平面上n条折线所界定的区域的最大个数是Zn
- 研究小的、基础的情形
Z0 = 1;Z1 = 2;Z2 = 7
从这些小的情形出发,会发现除了这“两条”直线不经过它们的交点延伸出去,从而而使得区域相融合之外, 一条折线与两条直线相似: - 求出递归式
区域2、3、4对于两条直线来说它们是不同的区域,但在一条折线的情形下是单独的一个区域,也就是每一条折线对于两条直线来说,丢失了2个区域。如果放置得当——锯齿点必须放在它与其他直线的交点“之外”——那2个区域就是我们失去的全部,也就是说,对每条折线我们仅仅损失了2个区域:
Zn = L2n - 2n , n>=0 - 求出封闭式
Zn = 2n(2n+1)/2 + 1 - 2n = 2n^2 - n + 1,n>=0
4)平面上的Z形线
问题描述:不错,这也是平面上的直线的变形,每条Z形线由两条平行的无限半直线和一条直线段组成,设平面上的n条Z形线所界定的区域的最大个数Wn
- 研究小的、基础的情形
W0 = 1;W1 = 2;W2 = 12 - 求递归式
法一:
在已有的图形基础上,为了能最多划分区域,务必让Z形线的3条线与已有的直线都相交,这样每一次划分的都将是目前所能划分的最大份数。假如已经有n-1条Z形线,那么平面上就会有3(n-1)条线,由于Z形线是平行的,所以添加一对平行线,会增加2个3(n-1)+1个区域,当把平行线的相连构成Z形线时,又增加了3(n-1)+1个区域,但是这时候,由于平行直线被截断为射线,导致两个区域合成一个区域,所以又少了2个区域,由此得出以下递归式:
W0 = 1;Wn = Wn-1 + 3(3(n-1)+1) - 2 = Wn-1 + 9n - 8;
法二:假设已有n-1个Z形线,那么,多加一个Z形线,最好的情况是和每一个已存在的Z形线相交有9个交点,得出以下递归式:
W0 = 1;Wn = Wn-1 +9(n-1) + 1 = Wn-1 + 9n - 8; - 求封闭式
用累加法:得Wn = 1 + 9(n + n-1 + ... + 1) - 8n = (9n^2)/2 - 7n/2 + 1
5)约瑟夫问题
在介绍问题描述之前,我们先说一下这个问题的来源,这是一个很有意思的故事。
传说如果不是由于他的数学天赋,约瑟夫不会活到出名的那一天。在犹太罗马战争期间,他们41名犹太反抗者困在了罗马人包围的洞穴中。这些反抗者宁愿自杀也不愿被活捉,于是决定围成一个圆圈,并沿着圆圈每隔两个人杀死一个人,直到剩下最后两个人为止。但是,约瑟夫和一个未被告发的同谋者不希望无谓地自杀,于是他迅速计算出他和其朋友在这个险恶的圆圈中应该站的位置。
问题描述:从围成标有记号1到n的圆圈的n个人开始,每隔一个删去一个人,直到只有一个人幸存下来。(第一次,第一个人不会被删去,第二个人总是最先被删去的),设确定幸存者的号码J(n)
- 研究小的,基础的情形
J(1) = 1, J(2) = 1, J(3) = 3, J(4) = 1, J(5) = 3, J(6) = 5 - 求递归式
从小的情形不难发现,幸存者总是奇数,这是因为第一圈时就消除了所有的偶数号码。此外,如果n是偶数, 那么一圈之后,除了人数减半和号码变化之外,我们得到的是与一开始类似的情形。
也就是说
J(2n) = 2J(n) - 1, n>=1
类似的,对于奇数情形,有
也就是说
J(2n+1) = 2J(n) + 1, n>=1
由此得出以下递归式:
J(1) = 1;
J(2n) = 2J(n) - 1,n>=1;
J(2n+1) = 2J(n) + 1,n>=1; - 求封闭式
有了递归式,我们可以对很小的值做一张表,如下:
从表中可以看出,可以按2的幂将表中的数据分组,每一组的开始J(n)总是等于1,并且组里的数据每次递增2,因此,如果我们将n写成n=2^m + L的形式,其中2^m是不超过n的2的最大幂,而L则是剩下的数,那么递归式的解看起来是:
J(2^m + L) = 2L + 1,m>=0,0<=L<2^m - 证明封闭式
对m用归纳法:
基础->当m=0时必定有L=0,则J(1) = 1,结论为真
归纳->按L是偶数还是奇数而定
L是偶数,则m>0且2^m+L = 2n,J(2^m + L)=2J(2^(m-1)+L/2)-1=2(2L/2+1)-1=2L + 1
L是奇数 ,则m>0且2^m+L=2n+1, J(2^m+L)=2J(2^(m-1)+(L-1)/2)+1=2(2(L-1)/2+1)+1=2L+1
证毕。
四、约瑟夫问题推广
既然已经决解了约瑟夫问题,下面就来研究以下一个容易的问题:问题的每一个解都可以加以推广,使得它能应用于一类更为广泛的问题。一旦掌握了一项技巧,我们就应仔细琢磨看利用它能走多远,这是一件很有启发意义的事情。
1)二进制展开式
假设n的二进制展开式是 n = (bmbm-1...b1b0)2 (bi = 0, 1)
即 n = bm2^m + bm-12^(m-1) + ... + b12 + b0
对于n = 2^m + L,首位数字bm=1有
n = (1bm-1bm-2...b1b0)2
L = (0bm-1bm-2...b1b0)2
2L= (bm-1bm-2...b1b00)2
2L+1= (bm-1bm-2...b1b01)2
J(n) = (bm-1bm-2...b1b0bm)2
于是我们证明了
J((bmbm-1...b1b0)2) = (bm-1bm-2...b1b0bm)2
用计算机程序设计的话说就是,n向左循环移动一位就得到J(n)。这是不是不可思议!
现在我们用循环移位,一步就能求出约瑟夫问题的结果。
2)推广--成套方法
如下递归式:F(1) = a; 原来的递归式是:F(1) = 1; (a=1)
F(2n) = 2F(n) + b, n>=1; F(2n) = 2F(n) - 1; (b=-1)
F(2n+1) = 2F(n) + c, n>=1; F(2n+1) = 2F(n) + 1; (c=1)
对小的n值构成如下一般性的表:
看起来,a的系数不超过n的2 的最大幂,此外,在2的幂之间,b的系数递减1直到为0,而c的系数从0开始递增1.
如果把F(n)对a、b、c的依存关系分离开来,我们就可以把它表示成:
F(n) = A(n)a + B(n)b + C(n)c (式4-1)
看起来有 A(n) = 2^m (n = 2^m + L,0<=L<2^m,n>=1) (式4-2)
B(n) = 2^m -1 -L
C(n) = L
那么如何求a、b、c呢?可以从一个简单的函数F(n)出发,比如常数函数F(n)=1带入递归式:
1 = a;
1 = 2 + b;
1 = 2 + c; 求得a = 1, b = -1, c = -1
类似的,我们可以带入F(n) = n :
1 = a;
2n = 2n + b;
2n+1 = 2n + c 求得a = 1, b = 0, c = 1
只要碰到上面这种形式的递归式,就可以把递归式中的a,b,c和式4-2带入式4-1之中,从而得出F(n)。
3)延伸1
递归式修改为如下形式:
B0 = b,B1 = c
F(1) = a;
F(2n + j) = 2F(n) + Bj,j=0,1,n>=1
这个递归式按二进制展开是:
F((bmbm-1...b1b0)2) = 2F((bmbm-1...b1)2) + Bb0 (j=b0)
= 4F((bmbm-1...b2)2) + 2Bb1 + Bb0
...
= 2^mF((bm)2) + 2^(m-1)Bb(m-1) + ... + 2Bb1 + Bb0
= 2^m a + 2^(m-1)Bb(m-1) + ... + 2Bb1 + Bb0
假如解除二进制的基数约束,允许任意的数字,而不仅仅0和1,则:
F((bmbm-1...b1b0)2) = (aBbm-1Bbm-2...Bb1Bb0)2
此时,小的情形的情况如下表,这个将更加容易看到规律:
假如,当n=100=(1100100)2时,原来的约瑟夫值a=1, b=-1, c=1,有
n = (1 1 0 0 1 0 0)2 = 100
F(n) = (1 1 -1 -1 1 -1 -1)2
=+64+32-16 -8 +4 -2 -1 = 73
4)延伸2
进一步加以推广,递归式:
F(j) = a(j), 1<=j<d
F(dn + j) = CF(n) + B(j), 0<=j<d, n>=1
它有变动基数的解: F((bmbm-1...b1b0)d) = ( a(bm) B(bm-1) B(bm-2) ... B(b1) B(b0) )C
例如,假设凑巧,给定递归式: F(1) = 34
F(2) = 5
F(3n) = 10F(n) + 76, n>=1
F(3n+1) = 10F(n) -2, n>=1
F(3n+2) = 10F(n) +8, n>=1
在此,d=3,C=10,a(1) = 34, a(2) = 5, B(0) = 76, B(1) = -2, B(2) = 8
希望计算F(19),有19 = (201)3,F(19) = F((201)3) = (5 76 -2)10 = 500 + 760 -2 = 1258
以上内容整理自《具体数学》。