hanoi(漢諾)塔問題C++的遞迴實現
阿新 • • 發佈:2019-02-14
Hanoi(漢諾)塔問題。這是一個古典的數學問題,是一個用遞迴方法解題的典型例子。問題是這樣的:古代有一個梵塔,塔內有3 個座A、B、C,開始時A座上有64個盤子,盤子大小不等,大的在下,小的在上。有一個老和尚想把這64個盤子從A座移到C座,但每次只允許移動一個盤,且在移動過程中在3個座上都始終保持大盤在下,小盤在上。在移動過程中可以引用B座,要求程式設計序輸出移動的步驟。
讀者是不大可能直接寫出移動盤子的每一個具體步驟的,請讀者實驗一下按上面的規律將5個盤子從A座移到C座,能否直接寫出每一步驟?
老和尚自然會這樣想:加入有另外一個和尚能有辦法將63個盤子從一個座移到另一座。那麼,問題就解決了。此時老和尚只需這樣做:
(1)命令第2個和尚將63個盤子從A座移到B座;
(2)自己將1個盤子(最底下的,最大的盤子)從A座移到C座;
(3)再命令第2個和尚將63個盤子從B座移到C座。
至此,全部任務完成了。這就是遞迴方法。但是,有一個問題實際上未解決:第2個和尚怎樣才能將63個盤子從A座移到B座?
為了解決將63個盤子從A座移到B座,第2個和尚又想:如果有人能將62個盤子從一個座移到另一座,我就能將63個盤子從A座移到B座,他是這樣做的:
(1)命令第3個和尚將62個盤子從A座移到C座;
(2)自己將1個盤子從A座移到B座;
(3)再命令第3個和尚將62個盤子從C座移到B座。
再進行一次遞迴。如此“層層不放”,直到後來找到第63個和尚,讓他完成將2個盤子從一個座移到另一座,進行到此,問題就接近解決了。最後找到第64個和尚,讓他完成將1個盤子從一個座移到另一座,至此,全部工作都已落實,都是可以執行的。
可以看出,遞迴的結束條件是最後一個和尚只需移一個盤子;否則遞迴還要繼續進行下去。
應當說明,只有第64個和尚的任務完成後,第63個和尚的任務才能完成。只有第2個到第64個和尚任務完成後,第1個和尚的任務才能完成。只是一個典型的遞迴的問題。
為便於理解,先分析講A做上3個盤子移到C座上的過程:
(1)將A座上2個盤子移到B座上(藉助C);
(2)將A座上1個盤子移到C座上;
(3)將B座上2個盤子移到C座上(藉助A)。
其中第(2)步可以直接實現。第(1)步又可用遞迴方法分解為:
1.1 將A上1個盤子從A移到C;
1.2 將A上1個盤子從A移到B;
1.3 將C上1個盤子從C移到B。
第(3)不可以分解為:
3.1 將B上1個盤子從B移到A上;
3.2 將B上1個盤子從B移到C上;
3.3 將A上1個盤子從A移到C上。
將以上綜合起來,可得到移動3個盤子的步驟為:
A→C,A→B,C→B,A→C,B→A,B→C,A→C。
共經歷7步。由此可推出:移動n個盤子熬經歷2n-1步。如移4個盤子經歷15步,移5個盤子經歷31步,移64個盤子經歷264-1步。
由上面的分析可知:將n個盤子從A座移到C座可以分解為以下3個步驟:
(1)將A上n-1個盤藉助C座先移到B座上;
(2)把A座上剩下的一個盤移到C座上;
(3)將n-1個盤從B座藉助於A座移到C座上。
上面第(1)步和第(3)步,都是把n-1個盤從一個座移到另一個座上,採取的辦法是一樣的,只是座的名字不同而已。為使之一般化可以將第(1)步和第(3)步表示為:
將"one"座上n-1個盤移到"two”座(藉助"three”座)。只是在第(1)步和第(3)步中,one、two、three和A、B、 C的對應關係不同。對第(1)步,對應關係是one對應A,two對應B,three對應C。對第(3)步,是:one對應B,two對應C,three 對應A。
因此,可以把上面3個步驟分成兩類操作:
(1)將n-1個盤從一個座移到另一個座上(n>1)。這就是大和尚讓小和尚做的工作,它是一個遞迴的過程,即和尚將任務層層下放,直到第64個和尚為止。
(2)將1個盤子從一個座上移到另一個座上。這是打和尚自己做的工作。
下面編寫程式。分別用兩個函式實現以上的兩類操作,用hanio函式實現上面第1類操作(即模擬小和尚的任務),用move函式實現上面第2類操作(模擬大和尚自己移盤),函式呼叫hanio(n,one,two,three)表示將n個盤子從"one”座移到"three”座的過程(藉助 “two”座)。函式呼叫move(x,y)表示將1個盤子從x座移到y座的過程。x和y是代表A,B,C座之一,根據每次不同情況分別取A、B、C代入。
程式如下:
讀者是不大可能直接寫出移動盤子的每一個具體步驟的,請讀者實驗一下按上面的規律將5個盤子從A座移到C座,能否直接寫出每一步驟?
老和尚自然會這樣想:加入有另外一個和尚能有辦法將63個盤子從一個座移到另一座。那麼,問題就解決了。此時老和尚只需這樣做:
(1)命令第2個和尚將63個盤子從A座移到B座;
(2)自己將1個盤子(最底下的,最大的盤子)從A座移到C座;
(3)再命令第2個和尚將63個盤子從B座移到C座。
至此,全部任務完成了。這就是遞迴方法。但是,有一個問題實際上未解決:第2個和尚怎樣才能將63個盤子從A座移到B座?
為了解決將63個盤子從A座移到B座,第2個和尚又想:如果有人能將62個盤子從一個座移到另一座,我就能將63個盤子從A座移到B座,他是這樣做的:
(1)命令第3個和尚將62個盤子從A座移到C座;
(2)自己將1個盤子從A座移到B座;
(3)再命令第3個和尚將62個盤子從C座移到B座。
再進行一次遞迴。如此“層層不放”,直到後來找到第63個和尚,讓他完成將2個盤子從一個座移到另一座,進行到此,問題就接近解決了。最後找到第64個和尚,讓他完成將1個盤子從一個座移到另一座,至此,全部工作都已落實,都是可以執行的。
可以看出,遞迴的結束條件是最後一個和尚只需移一個盤子;否則遞迴還要繼續進行下去。
應當說明,只有第64個和尚的任務完成後,第63個和尚的任務才能完成。只有第2個到第64個和尚任務完成後,第1個和尚的任務才能完成。只是一個典型的遞迴的問題。
為便於理解,先分析講A做上3個盤子移到C座上的過程:
(1)將A座上2個盤子移到B座上(藉助C);
(2)將A座上1個盤子移到C座上;
(3)將B座上2個盤子移到C座上(藉助A)。
其中第(2)步可以直接實現。第(1)步又可用遞迴方法分解為:
1.1 將A上1個盤子從A移到C;
1.2 將A上1個盤子從A移到B;
1.3 將C上1個盤子從C移到B。
第(3)不可以分解為:
3.1 將B上1個盤子從B移到A上;
3.2 將B上1個盤子從B移到C上;
3.3 將A上1個盤子從A移到C上。
將以上綜合起來,可得到移動3個盤子的步驟為:
A→C,A→B,C→B,A→C,B→A,B→C,A→C。
共經歷7步。由此可推出:移動n個盤子熬經歷2n-1步。如移4個盤子經歷15步,移5個盤子經歷31步,移64個盤子經歷264-1步。
由上面的分析可知:將n個盤子從A座移到C座可以分解為以下3個步驟:
(1)將A上n-1個盤藉助C座先移到B座上;
(2)把A座上剩下的一個盤移到C座上;
(3)將n-1個盤從B座藉助於A座移到C座上。
上面第(1)步和第(3)步,都是把n-1個盤從一個座移到另一個座上,採取的辦法是一樣的,只是座的名字不同而已。為使之一般化可以將第(1)步和第(3)步表示為:
將"one"座上n-1個盤移到"two”座(藉助"three”座)。只是在第(1)步和第(3)步中,one、two、three和A、B、 C的對應關係不同。對第(1)步,對應關係是one對應A,two對應B,three對應C。對第(3)步,是:one對應B,two對應C,three 對應A。
因此,可以把上面3個步驟分成兩類操作:
(1)將n-1個盤從一個座移到另一個座上(n>1)。這就是大和尚讓小和尚做的工作,它是一個遞迴的過程,即和尚將任務層層下放,直到第64個和尚為止。
(2)將1個盤子從一個座上移到另一個座上。這是打和尚自己做的工作。
下面編寫程式。分別用兩個函式實現以上的兩類操作,用hanio函式實現上面第1類操作(即模擬小和尚的任務),用move函式實現上面第2類操作(模擬大和尚自己移盤),函式呼叫hanio(n,one,two,three)表示將n個盤子從"one”座移到"three”座的過程(藉助 “two”座)。函式呼叫move(x,y)表示將1個盤子從x座移到y座的過程。x和y是代表A,B,C座之一,根據每次不同情況分別取A、B、C代入。
程式如下: