算法设计与分析——汉诺塔问题

问题描述:

a,b,c3个塔座。开始时,在塔座a上有一叠共n个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,,n,现要求将塔座a上的这一叠圆盘移到塔座b上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:

规则1:每次只能移动1个圆盘;

规则2:任何时刻都不允许将较大的圆盘压在较小的圆盘之上;

规则3:在满足移动规则12的前提下,可将圆盘移至a,b,c中任一塔座上。

设计思路:

需要多少次:hannio(int n)

圆盘数量只有两三个的时候大家都能想明白,就不细说了。如果我们不考虑实际步骤,即不去关心每一步到底怎么移动,只想得出具体需要的次数其实很简单。怎么考虑呢?设n个圆盘一共需要移动的次数为f(n),那怎么求解f(n)呢?仔细想想,不管具体步骤多么繁琐,当我们移动最后一个,即第n个圆盘的时候,情况一定是塔A上只剩下第n个圆盘,并且塔C上一个圆盘也没有,那么按照规则,此时剩余的n-1个圆盘全部在塔B上按照从小到大的顺序排列着。那之前的所有步骤相当于把前面的n-1层从塔A全部移动到塔B上,这和f(n-1)【即把n-1个圆盘从塔A移动到塔C上的次数】的次数显然相同;现在来看后面的步骤,当我们把第n个圆盘移动到塔C上后,此时剩余的n-1个圆盘还在塔B上,塔A上一个圆盘也没有,而塔C上只有一个最大的圆盘,后面的步骤就是把塔B上的n-1个圆盘移动到塔C上,因为塔C上最大的圆盘对移动剩余的圆盘没有影响【不会违反规则2】,此时剩余的步骤和f(n-1)【即把n-1个圆盘从塔A移动到塔C上的次数】的次数显然相同,那我们就可以得出:f(n)=f(n-1)+1 + f(n-1),即f(n)=2f(n-1)+1

核心代码:
int hannio(int n)
{
	if (n == 1)
		return 1;
	else
		return 2*hannio(n - 1)+1;
}

显然,直接用递归算法就可以得出所需的次数,那我们想知道具体步骤呢?

具体步骤:Hannio(int n, char a, char b, char c)

上面我们已经明白了具体的步骤划分,那么现在只需要加上具体的移动方向,不妨设解决n个圆盘的问题的具体步骤为Hannio,此时我们除了传进去n外,还要把ABC三个塔传进去,从哪个到哪个,(int n, char a, char b, char c)我们定义它为从A到C,中途借助了B;首先要判断有没有到达边界条件,即n=1,如果没有,再执行前半部分,即把前面的n-1层从塔A全部移动到塔B上,然后移动最后第n个圆盘,即Move(n, a, c),之后再执行后半部分,把塔B上的n-1个圆盘移动到塔C上,至此,我们便完成了整个递归过程。

核心代码:
void Move(int n, char a, char b)//从A移动到B
{
	cout << "把第" << n << "个圆盘从" << a << "移动到" << b << endl;
}
void Hannio(int n, char a, char b, char c)
{
	if (n == 1)
	{
		Move(n, a, c);//最后一步,把第一个圆盘从A移动到C
	}
	else
	{
		Hannio(n - 1, a, c, b);//把前面的n-1层从塔A全部移动到塔B上
		Move(n, a, c);//然后移动最后第n个圆盘,从A到C
		Hannio(n - 1, b, a, c);//把塔B上的n-1个圆盘移动到塔C上
	}
}

总结:

递归算法就是把问题大而化之,就像本题,我们把步骤分为前n-1个圆盘从A到B,再移动第n个圆盘从A到C,最后把剩余的n-1个圆盘从B到C移动,这样就可以一步步递归,从而把问题分解。当然,递归里面非常重要的前提是弄清楚边界,这道题里的边界就是最后n一步步减小最后到1时,只有一个圆盘的时候,只用移动一位,这个时候递归就结束了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值