Hanoi Tower問題
相傳在古印度聖廟中,有一種被稱爲漢諾塔 Hanoi 的遊戲。該遊戲是在一塊銅板裝置上,有三根杆(編號A、B、C),在A杆自下而上、由大到小按順序放置若干金盤(如下圖 —— 圖片來自百度百科 )。
遊戲目標:
把A杆上的金盤全部移到C杆上,並仍保持原有順序疊好。
操作規則:
每次只能移動一個盤子,並且在移動過程中三根杆上都始終保持大盤在下,小盤在上,操作過程中盤子可以置於A、B、C任一杆上。
分析解決:
或許我們可以很容易的想明白當只有2個或3個盤子時的解決辦法,但當盤子數更多的時候,我們就很難具體列舉出移動盤子的每一步,這時我們的常規思維便顯得收效甚微,因此我們可以利用遞歸的思想來解決這個問題。
我們可以將漢諾塔問題進行簡化,設共有n個盤子,我們可以把複雜的解決辦法拆分爲如下三個步驟:
- 將 n - 1 個盤子從 A 杆移到 B 杆 ( 將除了最底部的那個盤子以外的所有盤子看作是一個整體 )
- 將第 n 個盤子從 A 杆移到 C 杆 ( 最底部的那個盤子)
- 將 n - 1 個盤子從 B 杆移到 C 杆
以此類推,我們可以將 n 個盤子的移動問題轉化爲 n - 1 個盤子的移動問題,再轉化爲 n - 2 個盤子的問題,最終轉化爲 1 個盤子的移動問題。
按照搬動規則,必須有三個柱子才能完成搬動,一個柱子作爲搬動源,一個柱子作爲搬動目的地,另一個柱子在中間過渡使用。在搬動過程中,三個柱子的作用是動態變化的,因此在函數中三個柱子必須指定,令其作爲函數的參數。相關代碼如下:
print("規則:將所有的盤子從a柱移到c柱\n")
while True:
num = int(input("請輸入盤子數:"))
if (num <= 0):
print("Error!")
break
count = 0
def hanoi(num,a,b,c):
global count
if(num == 1): #遞歸出口
count += 1
print("%d : %c -> %c" % (num,a,c))
else: #遞歸式子
hanoi(num-1,a,c,b)
print("%d : %c -> %c" % (num,a,c))
count += 1
hanoi(num-1,b,a,c)
hanoi(num,'a','b','c')
print("需要移動的總次數爲:%d\n" % count)
歸納總結:
遞歸的實質就是把問題進行簡化,簡化成形式相同、但較簡單一些的情況,編寫程序時只需要給出統一形式的遞歸式子,到運行時再由計算機逐層展開。程序中每經歷一次遞歸,問題就得到進一步簡化,不斷的簡化下去,直至抵達遞歸出口,就停止遞歸了。
在運用遞歸思想時,最重要的就是要時刻提醒自己,編寫程序時只需要給出運算規律,具體實現細節應該讓計算機去處理。千萬不能鑽到細節的實現中去,否則就會陷入實現細節的泥沼中很難理清頭緒。