遞歸-漢諾塔問題


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

數學抽象:如下圖所示,從左到右有A、B、C三根柱子,其中A柱子上面有從小疊到大的n個圓盤,現要求將A柱子上的圓盤移到C柱子上去,期間只有一個原則:一次只能移到一個盤子且大盤子不能在小盤子上面,求移動的步驟和移動的次數;

遞歸問題:遞歸是函數調用函數自身;如果一個大型復雜的問題能蹭蹭轉化為一個與原問題相似的規模較小的問題,那么就能用遞歸來進行求解;一般來說遞歸需要有邊界條件、遞歸前進端(子問題)和遞歸返回段(遞歸出口);當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。

遞歸函數設計技巧:

  • 遞歸主題;
  • 遞歸函數參數;
  • 遞歸函數出口;
  • 遞歸問題分析順序:從大問題分析小問題,每次利用減治思想減少規模;

遞歸算法解決問題的種類:

  • 數據的定義是按照遞歸定義的;(Fibonacci 函數)
  • 問題的解法是按照遞歸算法進行實現;(漢諾塔問題)
  • 數據的結構的形式是按照遞歸定義的;(二叉樹,圖問題,線性表:DFS搜索,歸並排序,快速排序等)

漢諾塔問題遞歸分析:

假設一共有n個圓盤,則漢諾塔問題,以遞歸角度進行分析為:

  • 把n-1個盤子由A移動到B;(借助輔助塔C)
  • 把第n個盤子,由A移動到C;
  • 把n-1個盤子由B移動到C; (借助輔助塔A) 

游戲解法:游戲要求從A->C移動;手動操作時:首先確定層數n, 如果層數是奇數,最上層由A->C; 如果層數為偶數,最上層A->B;

程序解法:

#include <iostream>
using namespace std;
int m = 0; // 移動次數

void move(int disk, char from, char to){
    cout << "移動次數:" << (++m) <<" 把塊:" << disk << " 按照如下移動:" <<  from << " --> " << to << endl;
}

// 遞歸求解漢諾塔
void hanoi(int disks, char from, char to, char assist){
    if (disks == 1) // 遞歸出口;
    {
        move(disks, from, to); 
        return; 
    }
    //遞歸子問題;
    hanoi(disks-1, from, assist, to); // n-1個盤子,由A移動到B, 借助輔助塔C;
    move(disks, from, to); // 把第n個盤子,由A移動到C;
    hanoi(disks-1, assist, to, from); // 把n-1個盤子,由B移動到C, 借助輔助塔A;
}

int main(){
    cout << "漢諾塔問題:" << endl;
    int n = 3;
    cout << "漢諾塔圓盤個數:" << n << endl;
    // 創建三個塔;
    char A = 'A';
    char B = 'B';
    char C = 'C';
    // 遞歸求解漢諾塔,輸出移動步驟;
    // n 個盤 從 A 塔移動到 C塔, 借助輔助塔B;
    hanoi(n, A, C, B); // 漢諾塔遞歸求解;
    return 0;
}
漢諾塔程序模板
bash-3.2$ c++ 漢諾塔問題.cc; ./a.out
漢諾塔問題:
漢諾塔圓盤個數:1
移動次數:1 把塊:1 按照如下移動:A --> C
bash-3.2$ c++ 漢諾塔問題.cc; ./a.out
漢諾塔問題:
漢諾塔圓盤個數:2
移動次數:1 把塊:1 按照如下移動:A --> B
移動次數:2 把塊:2 按照如下移動:A --> C
移動次數:3 把塊:1 按照如下移動:B --> C
bash-3.2$ c++ 漢諾塔問題.cc; ./a.out
漢諾塔問題:
漢諾塔圓盤個數:3
移動次數:1 把塊:1 按照如下移動:A --> C
移動次數:2 把塊:2 按照如下移動:A --> B
移動次數:3 把塊:1 按照如下移動:C --> B
移動次數:4 把塊:3 按照如下移動:A --> C
移動次數:5 把塊:1 按照如下移動:B --> A
移動次數:6 把塊:2 按照如下移動:B --> C
移動次數:7 把塊:1 按照如下移動:A --> C
漢諾塔輸出樣例

通過運行結果可以發現:總的移動次數為:2^n-1次;n為圓盤個數;

程序地址:https://github.com/yaowenxu/codes/blob/master/遞歸/漢諾塔問題.cc 

保持更新,轉載請注明出處;更多內容請關注cnblogs.com/xuyaowen;

參考鏈接:*文中圖來自於參考鏈接,如侵權請私信我更換;

漢諾塔的圖解 如何理解漢諾塔的遞歸?


免責聲明!

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



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