漢羅塔問題


 

懶漢式遞歸——瞬間明白漢諾塔問題

Q. 為什么會有遞歸?

A. 因為我們是人,不是電腦!我們的working
memory有限!

游戲規則:

有A,B,C三根針,將A針上N個從小到大疊放的盤子移動到C針,一次只能移動一個,不重復移動,小盤子必須在大盤子上面。

 

問題:

總的移動次數是多少?

 

分析:

首先明確,我們的目標是將A針上所有N個盤子移動至C針。而對於B針,我們可以將之看成一個中轉站。

這個問題,順向思維或者逆向思維道理是相同的,都太麻煩。我們不妨從中間開始思考。

||: 規則要求小盤子必須在大盤子之上。試想這個過程中,必然會經歷那么一個步驟,即有一大坨N-1個盤子在B針這個中轉站,而我們正將最大那個盤子(即第N個盤子)從A針移動至C針。

 

【圖例】

 

只有經歷“移動最大盤子”這個步驟,余下的事情才有可能實現。而在此之前,我們所要做的事情,就是讓“移動最大盤子”這個步驟得以實現。

現在,游戲整個過程以“移動最大盤子”為中央,被分為了兩部分。即(前)“將那坨N-1個盤子從A針移動到B針”,(中)“移動最大盤子”,(后)“將坨N-1個盤子從B針移動到C針”。

這是我們意識到,(前)與(后)操作道理是相似的。不去管那個最大盤子,(前)是以C針為中轉站,(后)是以A針為中轉站。因此兩者所需的移動次數應當是相等的。這意味着我們只要計算出其中一者的移動次數,然而乘以2,在加上“移動最大盤子”的那1次,就是這場游戲的總移動次數了。

用數學語言表達,假設(前)“將N-1個盤子從A針移動到B針”所需次數為Hn-1,總移動次數為Hn,那么可以得出的關系就是:Hn=Hn-1
x 2 + 1.

其實當我們得出這個算式的時候,稍微聰明一點的人已經明白,這就是一個遞推公式,可以直接用此公式得出Hn的通解。

但是LZ比較笨,就是不明白,為什么這個公式就可以套用呢?

那么就干脆繼續思考吧。

讓我們再想象一個情景:最大那個盤子在剛剛從A針被移動到C針,而那坨N-1個盤子還在B針蠢蠢欲動地等待着,即處於(中)->(后)的這個狀態。

怎么移動這N-1個盤子呢?

其實這時候,問題已經回到了筆者標示“||:”符號的地方。“||:”是樂譜中的反復記號,而我們要做的,就是重復上面的步驟,但是要將N替換為N-1,因為現在只剩下N-1個盤子需要移動。而中轉站則從B變成了A(鑒於這時盤子都在B針)。目標仍然是C針。下一次重復的時候,只剩下N-2個盤子需要移動,中轉站又回到B,目標不變仍然是C針。……整個過程中,變化的只是中轉站(在A與B之間輪換),以及剩下那些所需要移動的盤子的總數(越來越少)而已。

那么那個大盤子怎么辦?不去管它嗎??

正解!!

因為你已經把它移到C針,已經完成了這個移動步驟,它不會影響之后的操作。提醒自己牢記游戲規則,大盤子永遠在小盤子下面,而你也不需要再重復移動它——“不重復移動”,正是游戲規則的要求!

於是
Hn=Hn-1 x 2 + 1 這個公式,就可以套用、套用、套用……直到H3=7,H2=3,H1=1。

最后,用最懶的數學歸納法證明通項公式
Hn = 2^n - 1 吧!沒辦法,LZ就是比較懶嘛~

不管這個傳說的可信度有多大,如果考慮一下把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秒鍾的話,等到64個圓盤全部重新落在一起,宇宙被毀滅是什么時候呢?
讓我們來考慮一下64個圓盤重新摞好需要移動多少次吧。1個的時候當然是1次,2個的時候是3次,3個的時候就用了7次......這實在是太累了
因此讓我們邏輯性的思考一下吧。
3個的時候能夠移動最大的3盤時如圖所示。
到此為止用了7次。
接下來如右圖,在上面再放上3個圓盤時還要用7次(把3個圓盤重新放在一起需要的次數)。[4]  
因此,4個的時候是
“3個圓盤重新摞在一起的次數”+1次+“3個圓盤重新摞在一起需要的次數”
=2x“3個圓盤重新摞在一起的次數”+1次
=15次。
那么,n個的時候是
2x“(n-1)個圓盤重新摞在一起的次數”+1次。
由於1 個的時候是1次,結果n個的時候為(2的n次方減1)次。
1個圓盤的時候 2的1次方減1
2個圓盤的時候 2的2次方減1
3個圓盤的時候 2的3次方減1
4個圓盤的時候 2的4次方減1
5個圓盤的時候 2的5次方減1
........
n個圓盤的時候 2的n次方減1
也就是說,n=64的時候是(2的64次方減1)次。
因此,如果移動一個圓盤需要1秒的話,
宇宙的壽命=2的64次方減1(秒)
2的64次方減1到底有多大呢?動動計算器,答案是一個二十位的數字約是
1.84467440*10^19
用一年=60秒x60分x24小時x365天來算的話,大約有5800億年吧。
太陽及其行星形成於50億年前,其壽命約為100億年。
漢諾塔問題在數學界有很高的研究價值,而且至今還在被一些數學家們所研究。
也是我們所喜歡玩的一種益智游戲,它可以幫助開發智力,激發我們的思維。

印度傳說

和漢諾塔故事相似的,還有另外一個印度傳說:舍罕王打算獎賞國際象棋的發明人──宰相西薩·班·達依爾。國王問他想要什么,他對國王說:“陛下,請您在這張棋盤的第1個小格里賞給我一粒麥子,在第2個小格里給2粒,第3個小格給4粒,以后每一小格都比前一小格加一倍。請您把這樣擺滿棋盤上所有64格的麥粒,都賞給您的仆人吧!”國王覺得這個要求太容易滿足了,就命令給他這些麥粒。當人們把一袋一袋的麥子搬來開始計數時,國王才發現:就是把全印度甚至全世界的麥粒全拿來,也滿足不了那位宰相的要求。
那么,宰相要求得到的麥粒到底有多少呢?總數為
1+2+2^2 + … +2^63=2^64-1
等於移完漢諾塔所需的步驟數。我們已經知道這個數字有多么大了。人們估計,全世界兩千年也難以生產這么多麥子!
'''
source 原來的盤子
targer 移到目標柱子的盤子
helper 中間柱子的盤子
'''
def hanoi22(n,source,target,helper):
pass
def hanoi(n,A,B,C):
if n == 1:
print(A+'->'+B)
else:
hanoi(n-1,A,C,B)
print(A+'->'+B)
hanoi(n-1,C,B,A)

hanoi(3,'A','B','C')

 

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM