算法设计分析 ——汉诺塔(超详细)

汉诺塔问题
给定一个由n个圆盘组成的塔,这些圆盘按照大小递减的方式套在第一根桩柱上。现要将整个塔移动到另一根桩柱上,每次只能移动一个圆盘,且较大的圆盘在移动过程中不能放置在较小的圆盘上面。

输入格式:
输入由四行: 第一行是圆盘数量n(1<=n<=10); 第二行到第四行分别是三根桩柱的名字(字符串),n个盘子套在第一根桩柱上。

输出格式:
输出移动步骤,每行输出一步。

输入样例:
在这里给出一组输入。例如:

2
a
b
c

输出样例:
在这里给出相应的输出。例如:

a->b
a->c
b->c
 

分析,假设现在有三个柱子,分别为S、T、D,分别表示为原始柱子(即待移动盘子的柱子),T是临时柱子,表示S柱子上的一些盘子得借助T柱子才能移动到D柱子。D是目标柱子。现在怎么把S柱子上的所有盘子移动到D柱子,并且D柱子从底到上的盘子是从大到小的???

假设只有一个盘子,很简单,直接从S柱移动到D柱子,我们记为S->D,那如果是2个盘子,先把S柱子上面那个盘子放在T柱子上,即S->T,然后把S柱子下面那个盘子放在D柱子上,即S->D,最后把T柱子上的那个盘子放到D柱子即可,即T->D。现在如果是n个盘子呢??细心的同学已经发现了这是一个递归问题,可以先把n-1个盘子借助D柱子移动到T柱子,然后把S柱子最底下那个盘子移动到D柱子,然后再把n-1个柱子,借助S柱子移动到D柱。

代码如下:

void Han_nuo1(int n,char S, char T, char D)//S表示原始柱子,即一开始就有很多盘子待移动的柱子
//T表示S柱子借助T柱子到达D柱子,T是临时柱子,D表示目标柱子
{
	if (n == 1)//当只有一个盘子时,直接把盘子从S柱移动到D柱
	{
		printf("%c->%c\n",S,D);
	}
	else
	{
		Han_nuo1(n-1,S, D, T);//先把n-1个盘子借助D柱子移动到T柱
		printf("%c->%c\n",S,D);//再把剩下的一个盘子移动到D柱
		Han_nuo1(n-1,T, S, D);//最后把剩下的n-1个盘子借助S柱移动到D柱
	}
}

int main()
{
    char S='S', T = 'T', D = 'D';
    int n = 0;
    printf("输入S柱子上有几个盘子:\n");
    scanf("%d", &n);
    int* count=&n;
    Han_nuo1(n,S, T, D);
     system("pause");
     return 0;
}

运行结果:

当盘子大于20个时,会发现要移动的次数非常大,现在下面给出能计算移动次数的版本,假设每一动一个盘子就记为移动一次,不管是移动到哪个柱子上。

汉诺塔加强版如下:

void Han_nuo2(int n, char S, char T, char D, int* count)//S表示原始柱子,即一开始就有很多盘子待移动的柱子
//T表示S柱子借助T柱子到达D柱子,T是临时柱子,D表示目标柱子,count记录移动的次数
{
	if (n == 1)
	{
		printf("%c->%c\n", S, D);
		(*count)++;
	}
	else
	{
		Han_nuo2(n - 1, S, D, T, count);
		printf("%c->%c\n", S, D);
		(*count)++;
		Han_nuo2(n - 1, T, S, D, count);
	}
}

 int main()
 {
     char S = 'S', T = 'T', D = 'D';
     int n = 0;
     printf("输入S柱子上有几个盘子:\n");
     scanf("%d", &n);
     int count=0;
     Han_nuo2(n, S, T, D, &count);
     printf("%d\n", count);
     system("pause");
     return 0;
 }

 运行结果:

想必已经发现规律了,S柱子上要移动N盘子,移动的次数为2^N-1次,当盘子大于30个时,移动的次数是非常大的。 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值