描述
假设有不同大小的光碟从小到大的顺序从1到n编号。将这n个圆盘任意的套在这三根立柱上,立柱的编号分别为A、B、C,这个状态成为初始状态。 现在要求找到一种步数最少的移动方案,是的从初始状态转变为目标状态。 移动时有如下要求: 一次只能移动一个盘: 不允许把大盘移动到小盘上面。
第二行到第四行分别是初始状态中A、B、C柱上圆盘的个数和从下到上每个圆盘的编号;
第五行到第七行分别是目标状态中A、B、C柱上圆盘的个数和从下到上每个圆盘的编号;
最后一行输出最少的步数。
解:
这道题是明显的递归。为了后面函数编写方便,输入时可进行加工。可将“初始状态”和“目标状态”分为两个数组a和b。a[i]即表示i号的初始位置,b[i]则为目标位置。先按照题目的输入顺序输入,一旦输入i,则在a[i]中记录行数并转化为柱子的askll码,b[i]同理。为了节省存储空间,可用一个变量重复输入。接下来调用函数时可用循环,为了题目有关移动顺序的要求,从最大的n开始调用。函数需两个参数,为需移动的圆盘好k和要将其移动的位置t。若k的初始位置已在t上,可直接return。若没有,则先将k-1至1移动到辅助柱子上,这时就要用到循环并在循环中递归。循环完后,再将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);
}