W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
在歸并排序和構建二叉樹中,我們都是將原問題分解為兩個規(guī)模為原問題一半的子問題。然而對于漢諾塔問題,我們采用不同的分解策略。
Question
給定三根柱子,記為 A
、B
和 C
。起始狀態(tài)下,柱子 A
上套著 C
上,并保持它們的原有順序不變。在移動圓盤的過程中,需要遵守以下規(guī)則。
圖 12-10 漢諾塔問題示例
我們將規(guī)模為 A
移動至 C
的漢諾塔問題。
如圖 12-11 所示,對于問題 A
移動至 C
即可。
圖 12-11 規(guī)模為 1 問題的解
如圖 12-12 所示,對于問題 B
來完成移動。
A
移至 B
。A
移至 C
。B
移至 C
。圖 12-12 規(guī)模為 2 問題的解
解決問題 B
從 A
移至 C
。其中,C
稱為目標柱、B
稱為緩沖柱。
對于問題
因為已知 A
頂部的兩個圓盤看做一個整體,執(zhí)行圖 12-13 所示的步驟。這樣三個圓盤就被順利地從 A
移動至 C
了。
B
為目標柱、C
為緩沖柱,將兩個圓盤從 A
移動至 B
。A
中剩余的一個圓盤從 A
直接移動至 C
。C
為目標柱、A
為緩沖柱,將兩個圓盤從 B
移動至 C
。圖 12-13 規(guī)模為 3 問題的解
本質上看,我們將問題
至此,我們可總結出圖 12-14 所示的漢諾塔問題的分治策略:將原問題
C
從 A
移至 B
。A
直接移至 C
。A
從 B
移至 C
。對于這兩個子問題
圖 12-14 漢諾塔問題的分治策略
在代碼中,我們聲明一個遞歸函數(shù) dfs(i, src, buf, tar)
,它的作用是將柱 src
頂部的 buf
移動至目標柱 tar
。
hanota.cpp
/* 移動一個圓盤 */
void move(vector<int> &src, vector<int> &tar) {
// 從 src 頂部拿出一個圓盤
int pan = src.back();
src.pop_back();
// 將圓盤放入 tar 頂部
tar.push_back(pan);
}
/* 求解漢諾塔:問題 f(i) */
void dfs(int i, vector<int> &src, vector<int> &buf, vector<int> &tar) {
// 若 src 只剩下一個圓盤,則直接將其移到 tar
if (i == 1) {
move(src, tar);
return;
}
// 子問題 f(i-1) :將 src 頂部 i-1 個圓盤借助 tar 移到 buf
dfs(i - 1, src, tar, buf);
// 子問題 f(1) :將 src 剩余一個圓盤移到 tar
move(src, tar);
// 子問題 f(i-1) :將 buf 頂部 i-1 個圓盤借助 src 移到 tar
dfs(i - 1, buf, src, tar);
}
/* 求解漢諾塔 */
void solveHanota(vector<int> &A, vector<int> &B, vector<int> &C) {
int n = A.size();
// 將 A 頂部 n 個圓盤借助 B 移到 C
dfs(n, A, B, C);
}
如圖 12-15 所示,漢諾塔問題形成一個高度為 dfs()
函數(shù),因此時間復雜度為
圖 12-15 漢諾塔問題的遞歸樹
Quote
漢諾塔問題源自一種古老的傳說故事。在古印度的一個寺廟里,僧侶們有三根高大的鉆石柱子,以及
然而,即使僧侶們每秒鐘移動一次,總共需要大約
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: