(2014-4)Hanoi 塔问题

问题描述:

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柱子进行顶上最小的元素进行判断,把小一点的那个圆盘移动到大一点的那个圆盘
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值