遞迴求解漢諾塔問題

weixin_34087301發表於2018-05-08
  • 資料結構習題解析・鄧俊峰 課後習題

問題
有三根杆子A,B,C。A杆上有N個(N>1)穿孔圓盤,盤的尺寸由下到上依次變小。要求按下列規則將所有圓盤移至C杆:

  1. 每次只能移動一個圓盤
  2. 大盤不能疊在小盤上面
    提示:可將圓盤臨時置於B杆,也可將從A杆移出的圓盤重新移回A杆,但都必須遵循上述兩條規則。

問:如何移?最少要移動多少次?

8605641-9750fe94e59fac6d.jpg
漢諾塔

問題分析

  • 具體分析網上有個部落格解釋的十分詳盡,我自認不能比他解釋的更清楚,所以在此貼一下他的地址: 漢諾塔的理解

要把圓盤移至C杆,我們可以分為以下步驟:

  1. 先把堆在A杆上的前n-1根藉助C杆移到B杆上
  2. 再把A杆上剩餘的最後一個移到C杆上
  3. 最後再把B杆上的n-1個盤藉助A杆移到C上
  • 當碟子為0時遞迴結束

程式碼:

#include <iostream>
using namespace std;

/* diskNums 盤子數量,init 初始杆名稱,temp 臨時杆名稱,dest 目標杆名稱 */
void hanoi(int diskNums, string init, string temp, string dest);
void move(int diskNums, string init, string dest);

int main(int argc, const char * argv[]) {
    hanoi(3, "A", "B", "C");
    return 0;
}
void hanoi(int diskNums,string init,string temp,string dest){
    if (diskNums>0) {
        hanoi(diskNums-1, init, dest, temp);
        move(diskNums, init, dest);
        hanoi(diskNums-1, temp, init, dest);
    }
}
void move(int diskNums, string init, string dest){
    cout<<"No."<<diskNums<<" disks from "<<init<<" to "<<dest<<endl;
}

執行結果

No.1 disks from A to C
No.2 disks from A to B
No.1 disks from C to B
No.3 disks from A to C
No.1 disks from B to A
No.2 disks from B to C
No.1 disks from A to C
Program ended with exit code: 0

複雜度分析
由遞迴的基本條件推出遞推式:

T(1) = O(1)    對應 if(n>0),遞迴基

T(n) = 2*T(n-1) + O(1)    
對應下面這三個函式
hanoi(diskNums-1, init, dest, temp);
move(diskNums, init, dest);
hanoi(diskNums-1, temp, init, dest);

S(n) = T(n) + O(1) = 2*T(n-1) + 2*O(1)
S(n-1) = T(n-1) + O(1)
S(n) = 2*S(n-1)
     = 2^2*S(n-2)
     ......
     = 2^n-1*S(1)
     = 2^n

故有 T(n) = O(2^n)

相關文章