? ? ? ?本人最近在讀TAOCP,雖感叢書內容浩繁,難以在有限時間內研讀,但亦收獲頗豐。本文是在讀過“1.2.1 數學歸納法”(后文的“本篇”均指TAOCP 1.2.1)之后的思考,也包含本篇的關鍵內容,以供復習參考。
數學歸納法與廣義歸納法
? ? ? ?本篇是從數學歸納法開始的。稍有數學基礎的人都明白數學歸納法的內容:
假定需要證明P(n)對所有正整數n為真,那么可以:
(1) 證明P(1)為真
(2) 證明“如果P(1),P(2),......,P(n)全部為真,那么P(n+1)也為真”,這個證明應對任何正整數成立
? ? ? ?很容易看出,使用數學歸納法證明可以看成是一個輸出“P(n)為真”的程序/算法:
E1: k<-1,輸出P(1)的證明
E2: 如果k=n,那么結果已經輸出
E3: 輸出“因為已經證明了P(1),P(2),......,P(k),所以P(k+1)為真”
E4: k<-k+1,跳轉到E2
? ? ? ?那么我們為什么可以使用這樣的歸納思想與歸納法呢?雖然上面的算法看起來已經很簡明、正確,但是顯然數學歸納法涉及到了無窮的概念,我們是否需要證明數學歸納法的正確性呢?實際上數學歸納法的思想是將P(n)的正確性與正整數n的定義綁定,而正整數的定義天生就是歸納的,我們認為正整數的歸納定義是一種公理化的定義,無需證明,因此證明方式與正整數定義如出一轍的數學歸納法也無需證明。
? ? ? ?在證明一些難以表示為P(n)這樣僅與一個正整數變量有關,而至少要表示成P(p,q)這樣含有多個正整數變量的命題時,上面的數學歸納法就顯得力不從心。有的方法會曲線救國:先證明P(1,1),再證明“P(1,1),P(2,1),......,P(p,1)為真可證明P(p+1,1)”與“P(p,1),P(p,2),......,P(p,q)為真可以證明P(p,q+1)”這兩條命題,分兩步得出結果。這不失為一個解決方案,但它沒有摸到歸納法的精髓。
? ? ? ?雖然數學歸納法作為一種古老的方法,依賴的是正整數的公理化歸納定義,但由它發展而來的廣義歸納法則是使用了集合與關系的理論,不僅能支持證明P(p,q),P(p,q,s)這樣的與正整數有關的命題,還擴充了命題自變量的范圍。
通過思考數學歸納法,我們可以樸素地將其思想總結為這樣:
如果我們能夠:
(1) 證明:“最開始”的命題;
(2) 證明:如果“所有排在前面”的命題都已經被證明,可以通過這些命題證明本命題。
那么就能證明這個命題“序列”里的任意一個命題。
? ? ? ?經過總結,我們可以提出在任意集合上的“良序”關系,借助這個關系,達到歸納證明的目的,不管集合的元素是不是同一類、是不是可數。
集合S上的良序關系@具備以下性質:
(i) 傳遞性
(ii) 任意S上的x、y,三種可能性:x@y,y@x,x=y恰有一種成立
(iii) 對S的任意非空子集A,A上存在元素x,使得A的任意元素y,都有x@y或x=y
? ? ? ?廣義歸納法推廣歸納法,在上面良序關系的基礎上說明了:如果在P(y)對于所有x@y均為真的假定下能夠證明P(x),那么P(x)對S中的所有x為真。
? ? ? ?對于從良序關系的定義,我們可以看到一點“樸素”的歸納法思想:(i)與(ii)保障了集合元素上有全序,我們可以構建“所有排在前面的命題”的列表用于證明當前命題;(iii)保障了“最開始的命題”的存在。顯然,正整數集上的“小于”關系就是良序關系。類似地,如果我們能夠對字符集合S定義一個良序關系,那么就可以對等長字符串集合T<sub>n</sub>(包含所有用來自S的字符構成的長為n的字符串)也定義一個良序:如果存在k (1 <= k <= n)使xj=yj對于1 <= j < k 恒成立,而xky<sub>k</sub>,那么在T<sub>n</sub>上(x<sub>1</sub>,x<sub>2</sub>,...,<sub>n</sub>)(y1,y2,...,yn).
歸納法成果:算法正確性證明
? ? ? ?許多算法包括分支、循環結構,應該如何使用有限的證明篇幅說明可能執行任意次分支、循環的算法的正確性呢?再復雜的算法也可以用流程圖表示它的有限個分支、循環步驟,利用廣義歸納法,我們可以找出每一個步驟之前的前提/斷言/不變量,然后證明經過這個步驟之后,后續步驟的前提/斷言/不變量是正確的。這要求在流程圖中:
如果指向某方框的至少一個箭頭上的斷言在執行方框內操作之前為真,那么離開該方框的相關箭頭上的所有斷言在執行方框內操作之后都為真。
? ? ? ?這樣一來,我們就可以用歸納的方法,說明在算法每一個步驟(方框)前的斷言都為真,也就包括“算法終止”的步驟,保證了算法終止時結論的正確性。
歸納思想成果:動態編程
? ? ? ?動態編程思想主要是:存儲可重用的中間計算結果;使用較小規模的計算問題答案擴展到較大規模的問題計算。這便應用了歸納思想。在經典的“曼哈頓地圖路徑”問題中,動態編程將輸入慢慢從(2,2)擴展到(m,n),實際上就是手動執行歸納的每一步。在現實的大部分問題中,解題使用(1,1)->(1,n),(m,1)->(m,n)的手段較多,并不會真正定義嚴格的良序并使用廣義歸納法。但是,如果要解決與字符串有關的問題,可以應用前文所提的良序定義與廣義歸納法,使算法正確性更加容易證明。