7-1 汉诺塔的非递归实现 (25 分)
借助堆栈以非递归(循环)方式求解汉诺塔的问题(n, a, b, c),即将N个盘子从起始柱(标记为“a”)通过借助柱(标记为“b”)移动到目标柱(标记为“c”),并保证每个移动符合汉诺塔问题的要求。
输入格式:
输入为一个正整数N,即起始柱上的盘数。
输出格式:
每个操作(移动)占一行,按柱1 -> 柱2的格式输出。
输入样例:
3
输出样例:
a -> c
a -> b
c -> b
a -> c
b -> a
b -> c
a -> c
代码
//单左双右,从小到大
#include"stdio.h"
#include"stdlib.h"
int main()
{
int N;
scanf("%d",&N);
int zhu[4][N+1];
//第零行中,第一个元素无用,其他元素代表每个盘子所在的行(即柱子)
//其他行每行代表一个柱子,每个一维数组的首个元素为last
zhu[3][0]=0;
zhu[1][0]=0;
zhu[2][0]=0;
char biaohao[5]=" abc";
//puts(biaohao);
//空格吃一个空间,使第一个柱子对应a,以此类推
for(int aa=N;aa>0;aa--)//给源柱子加上盘子
{
zhu[1][0]+=1;
zhu[0][zhu[1][0]]=1;//记录所有盘子都在第一行
zhu[1][zhu[1][0]]=aa;
//printf("%d",zhu[1][zhu[1][0]]);
}
int sum=0;//左移还是右移
if(N%2==0)
sum=1;
else
sum=-1;
int start=1;//准备从哪个柱子开始移动,值为柱子号
int next=start+sum;//将移动到的柱子号
int dang=1;//当前所移动的盘子号
int flag=-1;//当前盘子是否移动成功,0为否,1为真
int Z=0;//需要的总步数
while(zhu[3][0]!=N)
{
flag=-1;
if(next>3)
next=1;
if(next<1)
next=3;
if(zhu[next][0]==0||zhu[start][zhu[start][0]]<zhu[next][zhu[next][0]])
{
zhu[next][0]+=1;
zhu[next][zhu[next][0]]=zhu[start][zhu[start][0]];
//盘子向右移动
zhu[0][zhu[next][zhu[next][0]]]=next;
//更新刚刚所移动的盘子所在的柱子号
zhu[start][0]-=1;
//Z+=1;
//printf("第%d步:%c->%c\n",Z,biaohao[start],biaohao[next]);
printf("%c -> %c\n",biaohao[start],biaohao[next]);
flag=1;
}
if(flag==1||next==start)
//前者为移动成功,后者为移动失败(移动失败时,next必转到start,此时也刚好是一圈)
{
dang+=1;
if(dang==N+1)
dang=1;
while(dang!=zhu[zhu[0][dang]][zhu[zhu[0][dang]][0]])
//当当前所要移动的盘子不在其柱子的顶层时进入循环
{
dang+=1;
if(dang==N+1)
dang=1;
}
start=zhu[0][dang];//更新将移动的盘子所在的柱子号
// printf("start为%d\n",start);
next=start+sum;
}
else
next+=sum;
//printf("现在dang是%d ,start是%d,next是%d\n",dang,start,next);
}
//printf("共需要%d步",Z); //耗时1天。。
}