新哈诺塔题解


描述

假设有不同大小的光碟从小到大的顺序从1到n编号。将这n个圆盘任意的套在这三根立柱上,立柱的编号分别为A、B、C,这个状态成为初始状态。 现在要求找到一种步数最少的移动方案,是的从初始状态转变为目标状态。 移动时有如下要求: 一次只能移动一个盘: 不允许把大盘移动到小盘上面。


输入
第一行是状态中圆盘总数;(总数<=45)
第二行到第四行分别是初始状态中A、B、C柱上圆盘的个数和从下到上每个圆盘的编号;
第五行到第七行分别是目标状态中A、B、C柱上圆盘的个数和从下到上每个圆盘的编号;
输出
每一行一步移动方案,格式为:move I from P to Q
最后一行输出最少的步数。




解:


这道题是明显的递归。为了后面函数编写方便,输入时可进行加工。可将“初始状态目标状态分为两个数组aba[i]即表示i号的初始位置,b[i]则为目标位置。先按照题目的输入顺序输入,一旦输入i,则在a[i]中记录行数并转化为柱子的askll码,b[i]同理。为了节省存储空间,可用一个变量重复输入。接下来调用函数时可用循环,为了题目有关移动顺序的要求,从最大的n开始调用。函数需两个参数,为需移动的圆盘好k和要将其移动的位置t。若k的初始位置已在t上,可直接return。若没有,则先将k-11移动到辅助柱子上,这时就要用到循环并在循环中递归。循环完后,再将a[k]改为t(相当于进行移动),并打印,再将移动次数加一。


参考代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>


int n,s=0;
char a[46],b[46];

void move(int k,char t)
{
	if(a[k]==t)
	{
		return;
	}
	char h;
	if((a[k]==65&&t==66)||(t==65&&a[k]==66))
	{
		h=67;
	}
	if((a[k]==65&&t==67)||(t==65&&a[k]==67))
	{
		h=66;
	}
	if((a[k]==67&&t==66)||(t==67&&a[k]==66))
	{
		h=65;
	}
	for(int i=k-1;i>=1;i--)
	{
		move(i,h);
	}
	printf("move %d from %c to %c\n",k,a[k],t);
	a[k]=t;
	s++;
}

int main()
{
	scanf("%d",&n);
	int m,t;
	for(int i=1;i<=3;i++)
	{
		scanf("%d",&m);
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&t);
			a[t]=i+65-1;
		}
	}
	for(int i=1;i<=3;i++)
	{
		scanf("%d",&m);
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&t);
			b[t]=i+65-1;
		}
	}
	for(int i=n;i>=1;i--)
	{
		move(i,b[i]);
	}
	printf("%d",s);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值