借助堆棧以非遞歸(循環)方式求解漢諾塔的問題(n, a, b, c),
即將N個盤子從起始柱(標記為“a”)通過借助柱(標記為“b”)移動到目標柱(標記為“c”),
並保證每個移動符合漢諾塔問題的要求。
輸入格式:
輸入為一個正整數N,即起始柱上的盤數。
輸出格式:
每個操作(移動)占一行,按柱1 -> 柱2
的格式輸出。
輸入樣例:
3
輸出樣例:
a -> c a -> b c -> b a -> c b -> a b -> c a -> c
遞歸思路:
(1)先將 n - 1 個盤子從 a 通過 c 移動到 b 。
(2)再將最后一個盤子從 a 移動到 c 。
(3)最后將 n - 1 個盤子從 b 通過 a 移動到 c 。
遞歸代碼:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
void move(int n,char a, char b,char c) {
if (n == 1) {
printf("%c -> %c\n", a, c);
return;
}
move(n - 1, a, c, b);
printf("%c -> %c\n", a, c);
move(n - 1, b, a, c);
}
int main() {
int n; scanf("%d", &n);
move(n, 'a', 'b', 'c');
system("pause");
}
非遞歸思路:
(1)將最小圓盤移動到下一個柱子上
(2)對剩余兩柱子進行頂上最小的元素判斷,把小一點的圓盤移動到大一點的圓盤上(有空柱則摞在空柱子上)。
重復上述兩步就可以得到答案。
注意:這樣得到的最后的答案不一定是摞在 c 上,如果 N 是奇數將摞在 b 上,所以如果 N 是奇數我們就令第二個柱子為 c ,第三個柱子為 b ,這樣就一定最后是摞在 c 上的。
非遞歸代碼:
#define _CRT_SECURE_NO_WARNINGS//C++ 中使用 scanf 和 printf 會報錯 #include <iostream> #include <stack>
using namespace std; stack<int> s[3]; char name[3] = { 'a','b','c' }; void movemin(int a, int b) {//移動剩余兩柱子操作
//a 柱為空或 a 柱頂部圓盤大於 b 柱頂部圓盤,則將 b 柱頂部圓盤移動到 a 柱 if (s[a].empty() && !s[b].empty() || (!s[a].empty() && !s[b].empty() && s[a].top() > s[b].top())) { s[a].push(s[b].top()); s[b].pop(); printf("%c -> %c\n", name[b], name[a]); return; }
//圓盤由 a 柱移動到 b 柱 if (s[b].empty() && !s[a].empty() || (!s[a].empty() && !s[b].empty() && s[a].top() < s[b].top())) { s[b].push(s[a].top()); s[a].pop(); printf("%c -> %c\n", name[a], name[b]); return; } } int main() { int n; scanf("%d", &n);for (int i = n; i >= 1; i--) s[0].push(i); int now = 0; int before, after = 1; if (n % 2 == 1) {//n 為奇數 name[1] = 'c'; name[2] = 'b'; } while (true) {
//now 為最小圓盤所在柱 movemin(after, now);//(1)操作 if (s[after].size() == n) break; before = now; now = after; after = (now + 1) % 3; movemin(before, after);//(2)操作 } system("pause"); }
注意:使用 cin 和 cout 會超時,故使用 scanf 和 printf 輸入輸出。
(— 3— 好嘛,檢查了半天錯誤,以為是方法不對,結果發現 < 寫成 > 了。)