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