OpenJudge 函數遞歸練習(2)漢諾塔問題 詳解(簡單易懂)

3:漢諾塔問題

總時間限制:1000ms內存限制: 65536kB

描述

約19世紀末,在歐州的商店中出售一種智力玩具,在一塊銅板上有三根杆,最左邊的杆上自上而下、由小到大順序串着由64個圓盤構成的塔。目的是將最左邊杆上的盤全部移到中間的杆上,條件是一次只能移動一個盤,且不允許大盤放在小盤的上面。
這是一個著名的問題,幾乎所有的教材上都有這個問題。由於條件是一次只能移動一個盤,且不允許大盤放在小盤上面,所以64個盤的移動次數是:18,446,744,073,709,551,615
這是一個天文數字,若每一微秒可能計算(並不輸出)一次移動,那麼也需要幾乎一百萬年。我們僅能找出問題的解決方法並解決較小N值時的漢諾塔,但很難用計算機解決64層的漢諾塔。

假定圓盤從小到大編號爲1, 2, …

輸入

輸入爲一個整數後面跟三個單字符字符串。
整數爲盤子的數目,後三個字符表示三個杆子的編號。

輸出

輸出每一步移動盤子的記錄。一次移動一行。
每次移動的記錄爲例如 a->3->b 的形式,即把編號爲3的盤子從a杆移至b杆。

樣例輸入

2 a b c

樣例輸出

a->1->c
a->2->b
c->1->b

思路

對於這種遞歸的問題,不要太糾結於代碼是如何運行的,要宏觀的把握,把玩遊戲時候的步驟抽象起來,具體怎麼挪動讓程序去做。
對於此問題,是模擬連續發生的動作——在三根柱子上移動盤子

方法(來自北京大學 李戈老師):
  • 連續發生的動作是什麼?——假設有一個函數能給出答案:hanoi(n,x,z,y)表示有n個盤子,三個柱子標號爲x,y,z,盤子從 x 柱子藉助 z 柱子挪到 y 柱子。目標柱子爲 y(從左往右柱子序列爲x,y,z,y是中間的那個柱子,所有的盤子起始在x柱子上)
  • 不同動作之間的關係是什麼?——利用假定的函數分析如何解決問題:
    • hanoi(n-1,x,y,z) //首先要把最大的盤子上面的盤子(共n-1個),藉助目標柱子 y 移動到臨時柱子 z 上
    • n號盤子從 x 移到 y //讓最大的盤子(n號盤子)直接移動到目標柱子 y 上
    • hanoi(n-1,z,x,y) //將臨時柱子 z 上的n-1個盤子重複上面的過程求解
  • 遞歸終止的邊界條件是什麼?——最簡單的情況下的解:只有一個盤子,應該怎麼挪動
    • 這一個盤子直接 從 x 號柱子移動到 y 號柱子。

按照這種思路,不管起始柱子、目標柱子是哪個,都可以通過變換函數的參數位置來求解。

代碼

#include<iostream>
using namespace std;
void hanoi(int n,char x,char z,char y)
{
    if(n==1)
        cout<<x<<"->"<<n<<"->"<<y<<endl;
    else
    {
        hanoi(n-1,x,y,z);
        cout<<x<<"->"<<n<<"->"<<y<<endl;
        hanoi(n-1,z,x,y); //這裏也是n-1
    }
}
int main()
{
    int n;//盤子的數目
    char x,y,z;//杆子的編號
    cin>>n;
    cin>>x>>y>>z;
    hanoi(n,x,z,y);//n個盤子,從x藉助z移動到y;注意是從哪個柱子移動到哪個
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章