python汉诺塔_汉诺塔递归算法/搬金盘的婆罗门 - Python实现
漢諾塔遞歸算法/搬金盤的婆羅門 - Python實現
版權聲明本文節選自作者本人的圖書《Python編程基礎及應用》,高等教育出版社。本文可以在互聯網上自由轉載,但必須:注明出處(作者:海洋餅干叔叔)并包含指向本頁面的鏈接。本文不可以以紙質出版為目的進行改編、摘抄。本書同名免費MOOC《Python編程基礎及應用》在嗶哩嗶哩(B站)熱播,作者帶著你學。
17.1 漢諾塔問題
法國數學家愛德華·盧卡斯曾轉述過一個印度的古老傳說:在世界中心貝拿勒斯(在印度北部)的圣廟里,一塊黃銅板上插著三根金剛石柱。印度教的主神梵天在創造世界的時候,在其中一根石柱上從下到上的穿好了由大到小的64塊金盤,這就是所謂的漢諾塔 - Hanoi Tower。
按照梵天的命令,不論白天黑夜,總有一個婆羅門僧侶在按照下面的規則移動這些金盤:一次只移動一個盤,不管在哪根柱上,小盤必須在大盤上面。僧侶們預言,當所有的金盤都從梵天穿好的那根柱上移到另外一根柱上時,世界就將在一聲霹靂中消滅,而梵塔、廟宇和眾生也都將同歸于盡。
?
17.1.1 求解
如下圖所示的5個盤的漢諾塔問題,其總任務是將A柱上的n = 5個盤移至C柱。要實現這個總任務并且保證移盤過程中小盤始終在大盤上面,整個過程分三步實現。第1步:我們必須先將n - 1 = 4個黑盤從A柱移至B柱。在第1步的執行過程當中,為了保證規則的貫徹,顯然,必須借助于C柱作為中轉柱才能完成。
第1步所做的工作可描述為:借助中轉柱C, 將n-1=4個盤從A移至B。
? 現在,最大的白盤在A柱上,C柱是空的。可實施第2步:將A柱上的大盤取下,移至C柱。
接下來,我們要做的是第3步: 借助中轉柱A,將B柱上的n - 1 = 4個盤移至C柱。此時,C柱上雖然已經有了一個盤,但由于此盤是最大的,所以只要移動過程中不搬動C柱上的原有大盤,可以忽略其存在。
?
現在,我們試圖總結一下總任務及其三個子任務:
不難看出,除了柱子不同,子任務3同子任務1所做的工作是一樣的,都是把 n - 1 個盤從一個柱移至另一個柱。同時,子任務1,3與總任務之間也極其相似,除了需要移動的盤子數量差異外。
我們稱,將n - 1個盤子從A移至B的漢諾塔問題,與原問題 - 即“將n個盤子從A移至C的漢諾塔問題”的性質完全相同,區別僅在于問題的規模 - 需要移動的盤子數量稍小。我也稱為前者是原問題的子問題。
如果我們能將n - 1 = 4個盤子從A移至B,從B移至C,那么n = 5個盤子的漢諾塔問題可解。那么如何求解4個盤子的漢諾塔問題呢? 聰明的讀者已經有了答案。
? 下面的圖展示了這一過程:
上面的分析可以看出,5盤漢諾塔問題可以通過求解4盤漢諾塔問題來解決,4盤漢諾塔問題可以通過求解3盤漢諾塔問題來解決。同理,3盤漢諾塔問題可以通過求解2盤漢諾塔問題來解決,2盤漢諾塔問題可以通過求解一盤漢諾塔問題來解決。而一盤漢諾塔問題,由于問題的規模足夠小,可直接解決:把盤從原柱搬至目標柱即可。所以在前表中,我們稱其為“簡單任務”。
17.1.2 遞歸算法
根據前一小節描述的算法思想,我們可以寫出漢諾塔問題求解的遞歸算法。
#BasicHanoi.py def hanoi(n, a, b, c):if n == 1:movements.append(a + " --> " + c)else:hanoi(n - 1, a, c, b)movements.append(a + " --> " + c)hanoi(n - 1, b, a, c)movements = [] hanoi(5, 'A', 'B', 'C') print("Steps count:",len(movements)) print("The first 3 steps are:", movements[:3])函數hanoi(n,a,b,c)用于生成以b為中轉柱,將n個金盤從a移至c的移盤序列。可以看到,這個遞歸函數的執行過程跟前節的總任務-子任務分解完全一致。當n == 1時,只有一個盤子,簡單任務,直接移盤。如果n > 1,則分解為兩個 n - 1 的漢諾塔子問題,以及一個簡單移盤任務。子問題的求解以函數遞歸調用來解決。
上述代碼的執行結果如下:
Steps count: 31 The first 3 steps are: ['A --> C', 'A --> B', 'C --> B']上述結果表明,5盤漢諾塔問題共需要31次移盤。movements列表中按順序存儲了全部的移盤動作。
17.1.3 計算復雜性
使用前小節中的程序,作者嘗試計算了n = 5 … 12漢諾塔問題的移盤過程,得到下述移盤次數。
看起來,似乎n個盤的漢諾塔問題的移盤次數為2n-1。事實上,對移盤次數的數學分析可以證明這個結論。n盤的漢諾塔求解可以拆分成兩個n-1盤的漢諾塔求解再加上1次簡單移盤。如果用T(n)來表示n盤漢諾塔的移盤次數的話,函數T(n)可使用下述遞歸定義。
?
我們試著把遞歸函數消解成非遞歸函數。
令t = n - 1,有:
故n盤漢諾塔共需移盤2n-1次。那么,如果梵天規定的是64個金盤的話,總移動次數則為264-1 = 18446744073709551615。如果婆羅門僧侶是個熟練工,1秒挪一個盤,那么1小時可以移3600個盤,1年可移3600 x 24 x 365 = 31536000個盤(忽略閏年誤差)。那么,解64盤漢諾塔問題共需要(264-1)/31536000年,即大約5949億年。看起來,按照當前的人類知識,印度的古老智慧好像高估了地球的預期壽命。
讀者不要去嘗試計算hanoi(64,’A’,’B’,’C’),顯然,在你有限的人生里,是無法完成這件接近“無限”的大事的。而且,因為遞歸所導致的內存消耗,你有限的計算機內存也排除了這種可能性。
作者是無神論者,上述探討基于嚴謹的數學,作者不相信任何人格化的“上帝 ”。
本書同名免費MOOC《Python編程基礎及應用》在嗶哩嗶哩(B站)熱播,點擊加入,作者帶著你學。
Python編程基礎及應用 重慶大學 高等教育出版社,作者親授_嗶哩嗶哩 (゜-゜)つロ 干杯~-bilibili?www.bilibili.com總結
以上是生活随笔為你收集整理的python汉诺塔_汉诺塔递归算法/搬金盘的婆罗门 - Python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器人踩滑板_不死神草、飞行滑板…超20
- 下一篇: 电脑环境变量设置 java_如何设置自己