《資料結構和演算法》之漢諾塔
一,問題描述:
法國數學家愛德華·盧卡斯曾編寫過一個印度的古老傳說:在世界中心貝拿勒斯(在印度北部)的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。不論白天黑夜,總有一個僧侶在按照下面的法則移動這些金片:一次只移動一片,不管在哪根針上,小片必須在大片上面。僧侶們預言,當所有的金片都從梵天穿好的那根針上移到另外一根針上時,世界就將在一聲霹靂中消滅,而梵塔、廟宇和眾生也都將同歸於盡。
不管這個傳說的可信度有多大,如果考慮一下把64片金片,由一根針上移到另一根針上,並且始終保持上小下大的順序。這需要多少次移動呢?這裡需要遞迴的方法。假設有n片,移動次數是f(n).顯然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此後不難證明f(n)=2^n-1。n=64時,假如每秒鐘一次,共需多長時間呢?一個平年365天有31536000 秒,閏年366天有31622400秒,平均每年31556952秒,計算一下:18446744073709551615秒。這表明移完這些金片需要5845.54億年以上,而地球存在至今不過45億年,太陽系的預期壽命據說也就是數百億年。真的過了5845.54億年,不說太陽系和銀河系,至少地球上的一切生命,連同梵塔、廟宇等,都早已經灰飛煙滅。
圖1 模擬圖
二,問題分析
1,分解問題
在這個問題中,我們發現由於每次只能移動一個圓盤,所以在移動的過程中顯然要藉助另外一根針才行。也就是說第1步將1到63個盤子藉助Z移動到Y上,第3步將Y針上的63個盤子藉助X移動到Z針上。那麼我們把所有新的思路聚集為以下兩個問題:
問題一:將X上的63個盤子藉助Z移動到Y上;
問題二:將Y上的63個盤子藉助X移動到Z上。
2,分解解答
問題一的圓盤移動步驟為:
(1)先將前62個盤子移動到Z上,確保大盤在在小盤下
(2)再將最底下的第63個盤子移動到Y上
(3)最後將Z上的62個盤子移動到Y上
問題二的圓盤移動步驟:
(1)先將前62個盤子移動到X上,確保大盤在小盤下
(2)再將最底下的63個盤子移動到Z上
(3)最後將X上的62個盤子移動到Y上。
三,程式碼分析
#include <stdio.h> void move(int n, char x, char y, char z) { if( 1 == n) { printf("%c-->%c\n", x,z); } else { move(n-1,x,z,y); //將n-1個盤子從x藉助z移動到y上面 printf("%c-->%c\n",x,z); //將第n個盤子從x上移動到z上 move(n-1,y,x,z); //將n-1個盤子從u上藉助x移動到z上 } } int main() { int n; printf("請輸入漢諾塔的層數:\n"); scanf("%d",&n); printf("移動的步驟如下:\n"); move(n,'x','y','z'); return 0; }
在上面的程式碼中可以看到其中使用了遞迴的思想,不斷地呼叫move函式則最終可以說實現移動的效果。當n=3時的結果為圖2結果圖所示,有移動的步驟。