汉诺塔问题

汉诺塔由三根柱子(分别用 A,B,C 表示)和 n个大小互不相同的空心盘子组成。一开始 n个盘子都摞在柱子 A 上,大的在下面,小的在上面,形成了一个塔状的锥形体。

a.jpg

对汉诺塔的一次合法的操作是指:从一根柱子的最上层拿一个盘子放到另一根柱子的最上层,同时要保证被移动的盘子一定放在比它更大的盘子上面(如果移动到空柱子上就不需要满足这个要求)。求圆盘从A到C上的最小步数。

看下图,可得到递归操作。

代码如下:

#include <iostream>
using namespace std;
int sum;
void hannoi(int n, char a, char b, char c)
{
	if (n == 1) sum++;//最后一块的步数
	else
	{
		sum++;//每一次进入步数++
		hannoi(n - 1, a, c, b);//A--B通过C
		hannoi(n - 1, b, a, c);//B--C通过A
	}
}
int main()
{
	int n = 0;
	cin >> n;
	hannoi(n, 'A', 'B', 'C');
	cout << sum;
	return 0;
}

根据上面的递归可以发现:挪动次数f(n) = 2*f(n - 1) + 1

进一步可以得到 - - > f(n) = 2^n - 1的结论

3根柱子的结论我们得出来了,那4根呢?

奇怪的汉诺塔

汉诺塔问题,条件如下:

1、这里有 A、B、C和 D 四座塔。

2、这里有 n个圆盘,n 的数量是恒定的。

3、每个圆盘的尺寸都不相同。

4、所有的圆盘在开始时都堆叠在塔 A上,且圆盘尺寸从塔顶到塔底逐渐增大。

5、我们需要将所有的圆盘都从塔 A 转移到塔 D 上。

6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。

请你求出将所有圆盘从塔 A移动到塔 D,所需的最小移动次数是多少。

河内塔.jpg

 4根柱子问题需要转换成我们熟知的3根柱子问题来解决:4根可以看成是j个移动到某根柱子,待最后再移(类似于3根柱子问题中最后移动到C的那个盘子),然后将其他3根柱子和盘子按照常规3柱子问题,而原本1盘的一步,变成了j盘的j步

#include <iostream>
#include <istream>
using namespace std;
int sum;
int s[15], an[15];//存放3根柱子的 存放结果的
int main()
{
	for (int i = 1; i <= 12; i++)//3根柱子的结论
		s[i] = 2 * s[i - 1] + 1;
	memset(an, 0x3f, sizeof an);//将an中全放无穷大的数,这样取得的数一定可以进入
	an[0] = 0 ;
	for(int i = 1 ; i <= 12 ; i++)//i表示盘子数
	{
		for (int j = 0; j < i; j++)//j为没有移动的部分(顺序操作中首次的3根问题)
		{
			//最优j数未知,需要遍历,比较此次与上次相比的最少步数
			an[i] = min(an[i], 2 * an[j] + s[i-j]);//an[j]为顺序操作中的再次3根问题
			/*
			不能为an[i-j]
			(此时j表示移动数),
			因为j = 0时,an[i]*2+s[0] > an[i],且此时an[i]为最大数,
			记录出错。
			*/
		}
		cout <<an[i]<< endl;
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值