借助堆栈以非递归(循环)方式求解汉诺塔的问题(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 。
非递归思路:
(1)将最小圆盘移动到下一个柱子上
(2)对剩余两柱子进行顶上最小的元素判断,把小一点的圆盘移动到大一点的圆盘上(有空柱则摞在空柱子上)。
重复上述两步就可以得到答案。
注意:这样得到的最后的答案不一定是摞在 c 上,如果 N 是奇数将摞在 b 上,所以如果 N 是奇数我们就令第二个柱子为 c ,第三个柱子为 b ,这样就一定最后是摞在 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"); }
非递归代码:
#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"); }
— 3— 好嘛,检查了半天错误,以为是方法不对,结果发现 < 写成 > 了。