C++ 漢諾塔問(wèn)題知識(shí)點(diǎn)總結(jié)
漢諾塔問(wèn)題,是心理學(xué)實(shí)驗(yàn)研究常用的任務(wù)之一。當(dāng)然我們是學(xué)計(jì)算機(jī)的,因此我們嘗試用計(jì)算機(jī)去求解它。
例題
openjudge6261 漢諾塔問(wèn)題
描述
有一種智力玩具,在一塊銅板上有三根桿,最左邊的桿上自上而下、由小到大順序串著由n個(gè)圓盤(pán)構(gòu)成的塔。目的是將最左邊桿上的盤(pán)全部移到中間的桿上,條件是一次只能移動(dòng)一個(gè)盤(pán),且不允許大盤(pán)放在小盤(pán)的上面。這就是著名的漢諾塔問(wèn)題。
假定圓盤(pán)從小到大編號(hào)為1,2,3,……
輸入
輸入為一個(gè)整數(shù)后面跟三個(gè)單字符字符串。
整數(shù)為盤(pán)子的數(shù)目,后三個(gè)字符表示三個(gè)桿子的編號(hào)。
輸出
輸出每一步移動(dòng)盤(pán)子的記錄。一次移動(dòng)一行。
每次移動(dòng)的記錄為例如 a->3->b 的形式,即把編號(hào)為3的盤(pán)子從a桿移至b桿。
樣例輸入
2 a b c
樣例輸出
a->1->c
a->2->b
c->1->b
漢諾塔問(wèn)題
漢諾塔問(wèn)題的解決算法是一種經(jīng)典的分治算法,而分治算法最重要的三個(gè)步驟:
- 分解:如果說(shuō)我們要將num個(gè)盤(pán)子從原柱子l通過(guò)過(guò)渡柱子mid移動(dòng)到目標(biāo)柱子r,那么我們可以先把上面的(num - 1)個(gè)盤(pán)子從原柱子l移動(dòng)到過(guò)渡柱子mid,之后再把編號(hào)num的這個(gè)盤(pán)子移動(dòng)到目標(biāo)柱子r上,最后再把那(num - 1)個(gè)盤(pán)子從過(guò)渡柱子mid移動(dòng)到目標(biāo)柱子r,就成功了。
- 解決:用遞歸分別再去解決子問(wèn)題并輸出。(邊界條件:當(dāng)只有一個(gè)盤(pán)子既num == 1時(shí),直接輸出就好了)。
- 合并:遞歸回來(lái)的就是結(jié)果了,不用再合并。
簡(jiǎn)而言之,就是每次我們把第num個(gè)盤(pán)子單獨(dú)看成一個(gè)整體,剩下(num - 1)個(gè)盤(pán)子看成一個(gè)整體,之后對(duì)這兩個(gè)整體分別去進(jìn)行移動(dòng),使其到達(dá)目標(biāo)位置。
最后算一下時(shí)間復(fù)雜度,這里稍微有些難算。
假設(shè)i個(gè)盤(pán)子從一根柱子移動(dòng)到另一根柱子需要step(i)步
對(duì)于一個(gè)單獨(dú)的塔,程序會(huì)進(jìn)行以下操作:
- 將上面的(n - 1)個(gè)盤(pán)子移動(dòng)到過(guò)渡柱子,次數(shù)為step(n - 1)。
- 將第n個(gè)盤(pán)子移動(dòng)到目標(biāo)柱子,次數(shù)為1。
- 將過(guò)渡柱子上的(n - 1)個(gè)盤(pán)子移動(dòng)到目標(biāo)柱子,次數(shù)為step(n - 1)。
則可以得到遞推式
step(n) = 2 * step(n - 1) + 1
之后不停地遞推下去,就會(huì)得到
step(n) = 2^n * step(0) + 2^(n - 1) + 2^(n - 2) + ...... + 2^1 + 2^0
又因?yàn)?個(gè)盤(pán)子根本不用移,所以step(0) = 0
所以step(n) = 2^(n - 1) + 2^(n - 2) + ...... + 2^1 + 2^0
之后用等比數(shù)列的公式就可以推出:step(n) = 2^n^ - 1
我們發(fā)現(xiàn)移動(dòng)次數(shù)為2^n^ - 1,實(shí)際上這也是漢諾塔問(wèn)題最少的移動(dòng)次數(shù)。所以最后得出解決漢諾塔問(wèn)題的算法時(shí)間復(fù)雜度為O(2^n^)。
代碼
# include <cstdio> # include <iostream> # include <cmath> # include <cstring> # include <algorithm> using namespace std; int n; char a, b, c; // hanoi(num, l, mid, r)表示需要將num個(gè)盤(pán)子從柱子l通過(guò)柱子mid移動(dòng)到柱子r。 void hanoi(int num, char l, char mid, char r) { if (num == 1) printf("%c->%d->%c\n", l, num, r); else { hanoi(num - 1, l, r, mid); printf("%c->%d->%c\n", l, num, r); hanoi(num - 1, mid, l, r); } } int main() { scanf("%d", &n); cin >> a >> b >> c; hanoi(n, a, c, b); // 這里因?yàn)轭}目中是讓所有盤(pán)子從左面的柱子移動(dòng)到中間的柱子,既從a到b。 return 0; }
就是小編整理的全部相關(guān)知識(shí)點(diǎn),感謝大家的學(xué)習(xí)和對(duì)腳本之家的支持。
相關(guān)文章
C語(yǔ)言 動(dòng)態(tài)內(nèi)存分配詳解
這篇文章主要介紹了C語(yǔ)言 動(dòng)態(tài)內(nèi)存分配詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06淺析C++模板類(lèi)型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)
可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類(lèi)型的參數(shù),這篇文章主要介紹了C++可變參數(shù)模板的展開(kāi)方式,需要的朋友可以參考下2022-08-08MFC擴(kuò)展DLL中導(dǎo)出類(lèi)和對(duì)話(huà)框的實(shí)現(xiàn)方法
這篇文章主要介紹了MFC擴(kuò)展DLL中導(dǎo)出類(lèi)和對(duì)話(huà)框的實(shí)現(xiàn)方法,詳細(xì)講述了實(shí)現(xiàn)擴(kuò)展DLL中導(dǎo)出類(lèi)和對(duì)話(huà)框的具體步驟與方法,具有不錯(cuò)的實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10C++實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05