问题描述:
Hanoi 塔问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64 个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。
请编写程序,把A 柱上的n 个金片,搬动到C 柱(中间可以使用B 柱),使得搬动的次数最少。输入金片的个数n(1<=n<=64),输出总搬动次数,以及最后100 次搬动。如果搬动次数小于等于100 则全部输出;每个搬动占一行,加上是这第几次搬动的数字和”:”,格式见示例。
输入样例:
2
输出样例:
3
1:A->B
2:A->C
3:B->C
思路:
具体参考:
递归思路:【c语言】Hanoi塔问题
非递归参考思路:汉诺塔的非递归实现 (25分)
一个美国学者总结得到:所有的汉诺塔移动可以总结为重复的两步,我们假设现在最小的圆盘在a柱子上,柱子为a,b,c
第一步:将最小圆盘移动到下一个柱子上,也就是b
第二步:对a柱子和c柱子进行顶上最小的元素进行判断,把小一点的那个圆盘移动到大一点的那个圆盘(有空则摞在空柱子上)。
重复上述两步就可以得到答案。
注意:这样得到的最后的答案不一定是摞在c上,如果N是偶数将摞在b上,所以如果N是偶数我们就令第二个柱子为c,第三个柱子为b,这样就一定最后是摞在c上的。
非递归另一种思路:汉诺塔的非递归算法
#include <iostream>
#include <stack>
#include <cstdio>
#include <cmath>
using namespace std;
char s[4] = { ' ','A','B','C' };
//a[1] a[2] a[3]分别为ABC三个柱子对应的栈
stack<int> a[4];
int n = 0; //移动次数
int N; //圆盘个数
double temp;
int temp_int;
bool move(int before, int after) {
if (a[before].empty())
return false;
if (!a[after].empty())
if ((a[after].top() - a[before].top()) < 0)
return false;
a[after].push(a[before].top());
a[before].pop();
++n;
if(temp_int <= 100){
printf("%d:%c->%c\n", n, s[before], s[after]);//faster than cout
}
else{
if(temp_int - n < 100){
printf("%d:%c->%c\n", n, s[before], s[after]);
}
}
return true;
}
int main() {
int count = 0;
cin >> N;
temp = pow(2, N) - 1;
temp_int = (int)temp;
printf("%d\n", temp_int);
for (int i = 0; i < N; i++) //将所有盘子入栈,从大到小
a[1].push(N - i);
//这样得到的最后的答案不一定是摞在c上,如果N是偶数将摞在b上
//所以如果N是偶数我们就令第二个柱子为c,第三个柱子为b,这样就一定最后是摞在c上的
if (N % 2 == 1) {
s[2] = 'c'; s[3] = 'b';
}
while (++count) {
move((count - 1) % 3 + 1, (count) % 3 + 1); //将最小圆盘移动到下一个柱子上,也就是b
if (!move((count - 1) % 3 + 1, (count + 1) % 3 + 1) && !move((count + 1) % 3 + 1, (count - 1) % 3 + 1))
break; //对a柱子和c柱子进行顶上最小的元素进行判断,把小一点的那个圆盘移动到大一点的那个圆盘
}
}