1. 程式人生 > >遞迴——漢諾塔問題

遞迴——漢諾塔問題

引:遞迴求階乘

用遞迴演算法求n!
定義函式fact(n) = n!
則有fact(n) = n*fact(n-1)
已知fact(1) = 1

為了表達得更直觀清晰,定義兩個結點:“或結點”和“與結點”。
1. 或結點如圖9.1所示,圖中A為“或結點”,A依據不同的條件會有兩個不同的取值B或C。

9.1、9.2
2. 與結點如圖9.3所示,與結點要塗黑,相關聯的B與C之間要用弧線練起來。A為與結點,A的最終取值為C結點的值,但為了求得C的值,得先求出B結點的值,C時B的函式。仍以求n!為例畫出如圖9.4所示的與或圖。

9.3-9.5

  • 圖9.4中,A為或結點;B為直接可解結點,值為1(直接可解結點用圓圈中加一個黑點表示);C為與結點,當n>1時,A的取值即C的值,而C的值即E的值,為了求得E的值,需要先求出D的值。D值fact(n-1)乘以n即為E的值。

  • 與結點可能有多個相關聯的點,這時可描述為圖9.5。圖9.5中A結點的值最終為D的值,但為了求D,需先求B和C。從圖上看,先求左邊的點才能求最右邊的點的值,我們約定最右邊D點的值就是A結點的值。

下面以3!為例來畫與或結點圖,目的是體會遞迴的含義,見圖9.6。
9.6
圖9.7畫出了呼叫和返回的遞迴示意圖。
9.7
圖9.8為程式框圖
9.8
總結:遞迴過程相當於從菜心“推到”外層,但遞迴演算法的出發點不放在初始條件上,而放在求解的目標上,從所求的未知項出發逐次呼叫本身的求解過程,直到遞迴的邊界(即初始條件)。

漢諾(hanoi)塔問題

相傳在古印度聖廟中,有一種被稱為漢諾塔(Hanoi)的遊戲。該遊戲是在一塊銅板裝置上,有三根杆(編號A、B、C),在A杆自下而上、由大到小按順序放置64個金盤(如下圖)。遊戲的目標:把A杆上的金盤全部移到C杆上,並仍保持原有順序疊好。操作規則:每次只能移動一個盤子,並且在移動過程中三根杆上都始終保持大盤在下,小盤在上,操作過程中盤子可以置於A、B、C任一杆上。
這裡寫圖片描述

思路:
先從簡單的情況分析起:

  • 在A柱只有一隻盤子,這時只需將該盤從A搬至C,一次完成,記為move 1 from A to C。
  • 在A柱上有兩隻盤子,1為小盤,2為大盤(1在2上面)。
    1. 將1號盤從A移至B,這是為了讓2號盤能移動,記為move 1 from A to B。
    2. 將2號盤從A移至C,記為move 2 from A to C。
    3. 再將1號盤從B移至C,記為move 1 from B to C。
  • 在A柱上有3只盤子,從小到大從上到下分別為1號、2號、3號。
    1. 將1號盤和2號盤視為一個整體,先將二者作為整體從A移至B,給3號盤創造能夠一次移至C的機會。這一步記為move(2,A,C,B),意思是將上面的兩個盤子作為整體從A藉助C移至B。
    2. 將3號盤從A移至C,一次到位,記為move 3 from A to C。
    3. 處於B上的作為一個整體的兩個盤子,再移至C。這一步記為move(2,B,A,C),意思是將兩個盤子作為整體從B藉助A移至C。所謂藉助是什麼意思,等這件事完成了不言自明。
  • 從題目的約束條件看,大盤可以隨便摞小盤,相反則不允許。在將1號和2號盤作為整體從A移至B的過程中,move(2,A,C,B)實際上是分解為以下3步:
    1. move 1 from A to C。
    2. move 2 from A to B。
    3. move 1 from C to B。
  • 通過以上步驟,將1號和2號盤作為整體從A移至B,為3號盤從A移至C創造了條件。同樣,3號盤一旦到了C,就要考慮如何實現將1號和2號盤當作整體從B移至C的過程了。實際上move(2,B,A,C)也要分解為3步:
    1. move 1 from B to A。
    2. move 2 from B to C。
    3. move 1 from A to C。
  • 分析move(2,A,C,B),是說要從兩隻盤子從A搬至B,但沒有C是不行的,因為先要將1號盤從A移到C,給2號盤創造條件從A移至B,然後把1號盤從C移至B。看到這裡就能明白藉助C的含義了。因此,在構思搬遷過程的參量時,要把3個柱子都用上。
  • 定義搬遷函式move(n,A,B,C),物理意義是將n只盤子從A經B搬到C。考慮上面的分析可以將搬遷過程用圖9.14表示。
    9.14
  • 圖9.14中將move(n,A,B,C)分解為3步。這3步是相關的,相互依存的,而且是有序的,從左至右執行的。
    1. move(n-1,A,C,B),理解為將上面的n-1只盤子作為一個整體從A經C移至B。
    2. 輸出n : A to C,理解為將n號盤從A移至C,是直接可解結點。
    3. move(n-1,B,A,C),理解為將上面的n-1只盤子作為一個整體從B經A移至C。這裡顯然是一種遞迴定義,當在解move(n-1,A,C,B)時又可想到,將其分解為3步:
      1. 將上面的n-2只盤子作為一個整體從A經B到C,即move(n-2,A,B,C)。
      2. 第n-1號盤走從A直接移至B,即n-1 : A to B。
      3. 再將上面的n-2只盤子作為一個整體從C經A移至B,即move(n-2,C,A,B)。

下面以3只盤子為例畫出遞迴的與或圖,見圖9.15。
9.15
這個圖很像一棵倒置著的樹,結點move(3,A,B,C)是樹根,與結點是樹的分枝,葉子都是直接可解結點
圖9.16和圖9.17是為了能夠體會呼叫和返回的過程畫出的,目的是為了結合比例加深理解遞迴過程。
9.16
9.17

遞迴求解漢諾塔問題
#include <iostream>
using namespace std;

int step = 1;
void move(int, char, char, char);

int main()
{
    int n;//盤輸
    cin >> n;
    cout << "在3根柱子上移" << n <<"只盤的步驟為:" << endl;
    move(n,'A', 'B', 'C');
    return 0;
}

//以下函式是被主程式呼叫的函式
//函式名:move
//輸入:m,整形變數,表示盤子數目
//p,q,r為字元型變數,表示柱子標號
//返回值:無
void move(int m, char p, char q, char r)
{
    if(m==1) //如果m為1,則為直接可解結點
    {
        //直接可解結點,輸出移盤資訊
        cout << "[" << step << "] move 1 # from " << p << " to " << r << endl;
        step++;
    }
    else
    {
        move(m-1, p, r, q); //遞迴呼叫move(m-1)
        //直接可解結點,輸出移盤資訊
        cout << "[" << step << "] move " <<  m << " # from " << p << " to " << r << endl;
        step++;
        move(m-1, q, p, r); //遞迴呼叫move(m-1)
    }
}

input:
3
output:
在3根柱子上移3只盤的步驟為:
[1] move 1 # from A to C
[2] move 2 # from A to B
[3] move 1 # from C to B
[4] move 3 # from A to C
[5] move 1 # from B to A
[6] move 2 # from B to C
[7] move 1 # from A to C

相關推薦

[] - C語言

#include<stdio.h> //將n個盤子從x藉助y移動到z void move(int n,char x,char y,char z) { if (1==n) printf("%c-->%c\n",x,z); else { move(n-1,x,

【資料結構與演算法】

漢諾塔 漢諾塔是根據一個傳說形成的數學問題(關於漢諾塔): 有三根杆子A,B,C。A杆上有N個(N>1)穿孔圓盤,盤的尺寸由下到上依次變小。要求按下列規則將所有圓盤移至C杆: 每次只能移動一

python海龜turtle 的動畫實現

這裡僅限制7階漢諾塔,不過稍微改一下整體引數還是可以做到“任意”階數的。 主要用了遞迴和棧的想法,用turtle實現。 import turtle class Stack: def __init__(self): self.items = []

——問題

引:遞迴求階乘 用遞迴演算法求n! 定義函式fact(n) = n! 則有fact(n) = n*fact(n-1) 已知fact(1) = 1 為了表達得更直觀清晰,定義

歸——問題(python實現)

最大 大盤 其他 pytho 每次 直接 print int b- 規則 每次移動一個盤子 任何時候大盤子在下面,小盤子在上面 方法 假設共n個盤子 當n=1時: 直接把A上的一個盤子移動到C上(A->C) 當n=2時: 把小盤子從A放到B上(A->

java版資料結構與演算法—()

package com.zoujc.triangle; /** * 漢諾塔 */ class TowersApp { public static void main(String[] args){ doTowers(3,'A','B','C'); }

python 方法 斐波那契數列—

#普通方法生成 def feibo(n): a,b=0,1 print('0,1',end='') for i in range(n-1): a,b=b,a+b print(',{0}'.format(b),end='') #遞迴方法生成 def

Python問題演算法與程式

漢諾塔問題: 問題來源:漢諾塔來源於印度傳說的一個故事,上帝創造世界時作了三根金剛石柱子,在一根柱子上從上往下從小到大順序摞著64片黃金圓盤。上帝命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一回只能移動一個圓盤,只能移動在最頂端的圓盤。有預言說

函式中的“問題”

漢諾塔問題 漢諾塔問題是一個經典的問題。漢諾塔(Hanoi Tower),又稱河內塔,源於印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,任何時候,在

問題(棧和的實現)

前邊寫的數值轉換是利用棧的先進後出的性質儲存數字的各位數,行編輯是利用棧的只允許在一端進行操作的特性,迷宮問題中棧儲存走過的通道塊,棧還可以輔助遞迴的實現,漢諾塔就是一個典型的例子 漢諾塔問題描述:塔X上的圓盤全部移動到塔Z,且移動過程中,小盤始終位於大盤上方。解決思路就是欲將n個圓盤從X移動到

圖解,用Python實現經典

感謝漂流的雲的圖解漢諾塔問題(遞迴求解) (1)先從最簡單的模型開始,假如A柱有2個盤,我們的任務是把這兩個盤按照規則(小疊在大上)移到C柱。操作步驟如下所示: (2)現在把原始時A柱盤子數增加到100,那步驟不言而喻變得很複雜,但是我們可以通過一種方法把複雜的問題簡單化: 可能此時你會

經典題目-移動 https://www.cnblogs.com/dmego/p/5965835.html

一.起源:   漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個

《零基礎入門學習Python》(24)--

前言 這節課主要講解用遞迴的方法,實現漢諾塔的解答  知識點 這節課主要講解用遞迴的方法,實現漢諾塔的解答  對於遊戲的玩法,我們可以簡單分解為三個步驟: 1) 將前63個盤子從X移動到Y上。  2) 將最底下的第64個盤子從X移動

閱讀遞迴函式最容易的方法不是糾纏於它的執行過程,而是相信遞迴函式會順利完成它的任務。如果你的每個步驟正確無誤,你的限制條件設定正確,並且每次呼叫之後更接近限制條件,遞迴函式總是能夠正確地完成任務。——《C和指標》 一、遊戲規則 有三個塔,第一個塔上放了若干個盤子。要將這若干個盤子

Python呼叫_問題

遞迴函式的優點是定義簡單,邏輯清晰。理論上,所有的遞迴函式都可以寫成迴圈的方式,但迴圈的邏輯不如遞迴清晰。 使用遞迴函式需要注意防止棧溢位。在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大

資料結構--的幾個應用(求和,階乘,

定義     一個函式自己呼叫自己遞迴的條件             必須要有明確的終止條件         所處理的資

Java中的組織形式、類與物件、靜態的static關鍵字、最終的final關鍵字、方法傳參方式、(階乘、斐波那契數列、

Java程式的組織形式 Java程式需要把程式碼以類的形式組織起來,然後被Java編譯器編譯,再被JVM執行。Java程式是以類的結構為基礎的。 Java程式的基本要素 識別符號 識別符號命名規範 關鍵字(保留字) 關鍵字(保留字)具有專門的意義和用途

方法----問題

遞迴思想解決 漢諾塔問題 1 package Recursive; 2 3 public class TestHanoi { 4 public static void main(String[] args) { 5 hanoi(3,'A','B','C'); 6

的應用——斐波那契數列、(Java實現)

package ch06; public class Fibonacci { public static int getNumber(int n) { if(n == 1) { return 0; } else if(n == 2){

經典案例 python實現

背景資料:  漢諾塔:漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間