接上文:http://blog.csdn.net/jj12345jj198999/article/details/6600734
這是一個非常強大和靈活的方法。我們將證明,在使用這種想法時很多問題變得很簡單,這一點會讓你驚訝不已。我們將採用其中的幾種方法,並顯示它們在設計演算法時的強大力量。在我們討論的歸納法的各種變形方法中,我們主要討論巧妙的選擇歸納序列,增強歸納假設,更強的歸納法以及最大的反例四種方法。
我們的處理方法有兩種新奇之處。首先我們把看上去不同的演算法設計技術歸到同一個類別下,這將使得對一個新演算法的尋找更有條理性。其次,我們利用已知的數學證明技巧來設計演算法,這一點很重要,因為它開啟了利用在別的學科多年發展過程中形成的強大的技術進行演算法設計的時代。
一般而言,在演算法領域使用歸納法和數學證明技巧並不是第一次見到。歸納法在證明演算法正確性上已經使用了很長時間,人們通過把對演算法執行步驟的斷言,證明它們在最初情況下成立和它們在特定操作步驟下保持不變結合起來,從而驗證演算法的正確性。這種方法最初由哥特斯和馮諾依曼提出的,後來由弗洛伊德和其他人對其進一步發展。Dijkstra和格裡斯提出了一種和我們開發程式相似的方法,同時他們也給出了對其正確性的證明。儘管在此我們借鑒了他們的一些技術,但我們的重點卻不同:我們關注於高層次的演算法理念而不必下降到實際的程式層面。PRL和NuPRL(這裡不會翻譯,建議看http://www.cs.cornell.edu/info/projects/nuprl/book/node2.html)使用數學證明作為一個程式開發系統的基本構成。當然遞迴也被廣泛用於演算法設計之中(對於遞迴的詳細討論請看...)
我們的目標主要是用於教學,我們假設讀者對數學歸納法和基本的資料結構已經很熟悉。對於任意一種證明技巧我們會對其類比進行一個簡要的解釋,然後給出一個或多個演算法例子。對於給出的演算法例子我們重點關注於如何使用這種方法。我們的目的不是在於對一個演算法進行解釋從而協助一個程式員更容易地將其轉換為程式,而是通過一種更容易理解的方式對其進行解釋。這些演算法通過一種創造性的過程加以解釋而不是以一種成品的方式出現。我們教演算法的目標不僅僅是向學生展示如何解決當前特定的問題,同時也是協助他們解決未來新的問題。教學生如何把想法融入到演算法設計中和教學生解決方案的實現細節同樣重要。但前者通常要更難一些。我們相信我們的方法能夠加強對這種思維過程的理解。
儘管歸納法建議通過遞迴加以實現,但也未必如此。(事實上我們稱這種方法為歸納而不是遞迴,從而淡化遞迴實現的概念)在很多情況下,迭代也很容易,甚至儘管在演算法設計中我們心裡想的是使用歸納法(遞迴),但迭代卻更有效率。
本文中提到的這些演算法是經過篩選的,以便能更好的展現這種方法的魅力。我們選擇的是一些簡單的問題,在後續部分選擇一些更複雜的例子。我們發現很多固定的演算法在演算法設計課上第一次教授時可以使用這種方法。(使用這種方法的演算法導論書很快就要出來了)我們首先從三個簡單的例子入手,(至少使用歸納法讓他們看上去簡單了)然後我們展示一些數學證明技巧以及它們在演算法設計中類似的技巧,在每種情況下這種類比都在一個或多個例子中得到了闡明。
三個例子
計算多項式的值[Q1]
問題:給定一個實數序列an,an-1,...a1,a0和一個實數x,計算下面這個多項式的值
Pn(x)=an*x^n+an-1*x^(n-1)+...a1*x+a0
這個問題看上去並不像是一個使用歸納法求解直觀例子,儘管如此,我們將證明使用歸納法能夠直接帶來很不錯的解決方案。我們首先使用最簡單幾乎微不足道的方法求解,然後通過發現其中的變化,從而找到更好的解決方案。
這個問題涉及到n+2個數字。使用歸納法解決該問題的依據是對一個更小的問題進行求解。換句話說,我們盡量減小問題的規模,然後使用遞迴求解。(或者我們稱其為歸納)第一步嘗試是移除an,這將導致問題中計算的運算式變成:
Pn-1(x)=an-1*x^(n-1)+an-2*x^(n-2)+...+a1*x+a0
除了規模外這是一個同樣的問題。因此我們可以使用下面的假設運用歸納法對其進行求解:
歸納假設:我們已經知道如何去計算一個多項式,該多項式在x處的輸入項有an-1,...a1,a0(即我們知道如何計算Pn-1(x))
我們現在可以使用這假設運用歸納法來解決該問題。首先我們需要解決最基本的情況,也就是計算a0;這是很簡單的。然後我們必須表明如何通過藉助規模較小的問題的解決方案(這裡是Pn-1(x)的值)來解決原有問題(即計算Pn(x))。在該例子中這是很直觀的。我們僅僅需要計算x^n,乘以an然後加上Pn-1(x)即可。
在這一點上看上去使用歸納法很無聊因為它僅僅是複雜了一個簡單的解決方案,上面提到的演算法僅僅是按照多項式的數學方式對多項式從右至左進行計算而已。然而,我們很快就會看見這種方法的強大之處。
儘管這個演算法是正確的,但其並不是高效的。它需要n+n-1+n-2+...+1=n(n+1)/2次乘法和n次加法計算。現在我們略微改變一下歸納法的使用方法,從而得到一個更好的解決方案。