漢諾塔問題是乙個經典的問題。漢諾塔(hanoi tower),又稱河內塔,源於印度乙個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著若干片**圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,任何時候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動乙個圓盤。計算若干片金片全部移動到另外乙個針上時需要移動的最少步數。
要把n片圓盤從a柱子移動到c柱子上,第一步唯一的選擇是移動a最上面的那個圓盤,但是應該將其移到b還是c呢?很難確定。因為接下來的第二步、第三步……直到最後一步,看起來都是很難確定的。能立即確定的是最後一步:最後一步的盤子肯定也是a最上面那個圓盤,並且是由a或b移動到c——此前已經將n-1個圓盤移動到了c上。
先假設除最下面的盤子之外,我們已經成功地將上面的n-1個盤子移到了b柱,此時只要將最下面的盤子由a移動到c即可。如圖:
當最大的盤子由a移到c後,b上是餘下的n-1個盤子,a為空。因此現在的目標就變成了將這n-1個盤子由b移到c。這個問題和原來的問題完全一樣,只是由a柱換為了b柱,規模由n變為了n-1。因此可以採用相同的方法,先將上面的62個盤子由b移到a,再將最下面的盤子移到c……過程為:
將b柱子作為輔助,把a上的63個圓盤移動到b上
將a上最後乙個圓盤移動到c
將a作為輔助,把b上的62個圓盤移動到a上
將b上的最後乙個圓盤移動到c
…規律是每次都是先將其他圓盤移動到輔助柱子上,並將最底下的圓盤移到c柱子上,然後再把原先的柱子作為輔助柱子,並重複此過程。移動步數的規律為:每增加乙個盤子,它的移動步數就增加原來步數的一倍加1。如:我們已經知道5個盤子移動31步,那麼,6盤子就是31*2+1=63步。
因此使用教材(注:本人使用的教材為《計算機常用演算法與程式設計案例教程(第二版)》,主編為楊克昌)上遞迴的方式解決該問題,其遞迴關係為:g(n)=2g(n-1)+1,初始條件(遞迴出口)為:g(1)=1。(p106)
教材上的解法(p106—p107):
假設函式hanoimove(m, x, y, z)用於將n個圓盤由x移動到z,y作為輔助柱子。用下面的**實現這個移動過程:
void hanoimove(int m,char x,char y,char z) //顯示漢諾塔移動的過程
}
用下面的**實現移動次數的計數:
double hanoinum (int m)
如果將這個問題的盤子數量減為56個或更少,就不會出現的問題。但盤子數量為57個乃至更多的話,所走的步數是乙個天文數字。由於使用整型和浮點型變數,記憶體限制,會存在溢位的風險,如下圖
輸出結果可以看出,輸出步數的後三位變為0,與真實步數有差異。
教材上解決的對策是當輸出金片大於40時,控制輸出格式為「%0.4e」,即使用科學計算法解決溢位的問題,但是此方法會導致輸出的資料不準確,如下圖
因此,嘗試使用字串型別解決溢位問題。
金片移動步數的另一種規律用公式表達為:2^m-1,其中m為金片數量。這個思路提供了另一種用c語言解決漢諾塔問題的辦法,完整**如下:
#include int main()
else
} a[t+fi] = '\0';
if(fi) a[0] = '1';
} i = 0;
while(a[++i]);
a[i-1] = a[i-1]-'0'-1 + '0'; //公式2^n-1中的『-1』操作
printf("共需要%s步\n",a);
return 0;
}
執行結果:
通過執行結果可以看出,用字串變數可以解決資料溢位的問題。
試題 基礎練習 FJ的字串(漢諾塔) 遞迴
1.對於漢諾塔,給了k層的碟 和三個分別為a b c的柱子,碟都在a上。我們如何解決問題的呢?我們是將k 1層從a移動到b上,再將第k個碟子由a移動到c這個柱子上,再將k 1層移動到k的上面。至於k 1層如何移動我們不需要考慮。2.對於這兩層的關係,我們可以知道k層總的移動數就是k 1層移動的數量 ...
資料型別 字串
一字串 定義 它是乙個有序的字元的集合,用於儲存和表示基本的文字資訊 或 中間包含的內容稱之為字串 特性 1只能存放乙個值 2不可變 3按照從左到右的順序定義字元集合,下表從0開始順序訪問,有序 字串的常用操作 移除空白 strip 首字母大寫.capitalize 所有大寫 upper 統計字元長...
Python資料型別 字串型別
變數名 str 變數值 msg hello world print msg 0 print msg 1 msg hello n print len msg msg hello world print ello in msg print lo w not in msg res print hello ...