第二章 演算法效率分析基礎 page 55 漢諾塔問題
漢諾塔問題介紹: 在印度,有這麼一個古老的傳說:在世界中心貝拿勒斯(在印度北部)的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。不論白天黑夜,總有一個僧侶在按照下面的法則移動這些金片,一次只移動一片,不管在哪根針上,小片必在大片上面。當所有的金片都從梵天穿好的那根針上移到另外一概針上時,世界就將在一聲霹靂中消滅,梵塔、廟宇和眾生都將同歸於盡。
這個問題有一個優雅的遞迴解法,圖2.4 描述了這個解法。為了把個盤子從木樁 1 移到木樁 3(藉助木樁2),我們需要先把 個盤子遞迴地從木樁 1 移到木樁 2(藉助木樁 3),然後直接把最大的盤子(第
讓我們把前面的一般性方案應用到漢諾塔問題上去。顯然,我們可以選擇盤子的數量作為輸入規模的一個指標,盤子的移動也可以作為該演算法的基本操作。可以清楚地看到,移動的次數只依賴於,因此,對於有下列遞推等式:
當時,
另一個很明顯的事實是初始條件,因此,對於移動次數我們建立了下面的遞推關係:
當時,
我們還是使用反向替換法來解這個遞推式:
替換
替換
左邊前 3 個求和算式的模式預示著下一個算式將是:,對這個模式進行一般化處理,在做了 次替換以後,得到下式:
因為初始條件是在 的情況下確立的,所以必須讓 ,我們有下列方程來解遞推式(2.3):
這樣得到了一個指數級的演算法,即使 的值不算大,該演算法的執行時間也會長得無法想像。這並不是因為這個演算法不好。不難證明,對於這個問題來說, 這是可能提供的最高效的演算法。事實上,是這個問題本身決定了它在計算上的難度。儘管如此,這個例子還是揭示了一個具有普遍意義的重要觀點:
我們應該謹慎使用遞迴演算法,因為它們的簡潔可能會掩蓋它們的低效率.
如果一個遞迴演算法會不止一次地呼叫它本身,出於分析的目的,構造一棵它的遞迴呼叫樹是很有用的。在這棵樹中,節點相當於遞迴呼叫,我們可以用呼叫引數的值(或者是幾個引數的值)作為節點的標記。對於漢諾塔這個例子來說,它的遞迴呼叫樹在圖2.5中給出。 通過計算樹中的節點數,我們可以得到漢諾塔演算法所做呼叫的全部次數:
這個數字就像我們預測的那樣,和我們早先求得的移動次數是一致的。
那麼好多人會問64個圓盤移動到底會花多少時間?那麼古代印度距離現在已經很遠,這64個圓盤還沒移動完麼?我們來通過計算來看看要完成這個任務到底要多少時間?
我們使用通項式: 。當時 。
我們假設移動一次圓盤為一秒,那麼一年為31536000秒。那麼18446744073709551615/31536000約等於584942417355天,換算成年為5845.54億年。
目前太陽壽命約為50億年,太陽的完整壽命大約100億年。所以我們整個人類文明都等不到移動完整圓盤的那一天。
結論:漢諾塔問題通式如下