汉诺塔——递归

经典汉诺塔
问题描述:假设有3个分别命名为X,Y,Z的塔座,在塔座X上插有n个直径大小各不相同、依小到大编号为1,2,……n个圆盘。现要求将X轴上的n个圆盘移至塔座Z上并仍按同样顺序叠排,圆盘移动时必须遵守下列规则:
(1)每次只能移动一个圆盘;
(2)圆盘可以插在X,Y和Z中的任一塔座上;
(3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
求n个盘至少需移动的次数。
分析:设F[n]表示将n个盘从按规则从X柱移到Z柱至少需要移动的次数,显然,当n=1时,F[n]=1;当n>1时,我们将移动盘之的过程分为三步:
1,将X柱上的n-1个盘依靠Z柱移到Y柱上,这个需要F[n-1]步;
2,将X柱上剩下的一个盘(最大的盘)移到Z柱上,这个需要1步;
3,将Y柱上的n-1个盘依靠X柱移到Z柱上,这个需要F[n-1]步;
所以移完n个至少需要的步数F[n]=F[n-1]+1+F[n-1]=2*F[n-1]+1; 而F[1]=1;由以上两个等式可以推出求F[n]的一般式,即F[n]=2^n-1;

汉诺塔的算法就3个步骤:第一,把a上的n-1个盘通过c移动到b。第二,把a上的最下面的盘移到c。第三,因为n-1个盘全在b上了,所以把b当做a重复以上步骤就好了:

    对于第一步的分析,在单独看第一步的时候可以看做没有第nge盘,只有n-1个盘,需要做的事情就是将这n-1个盘从c柱移动到b柱,中间可以借助a柱,这样问题的规模就减小了1,然后依次这样递减下去直至递减到问题的规模为1的时候就是结束条件。

    对于第二步的分析,第二步比较简单,就只是移动一个盘子即可。

    对于第三步的分析,第三步和第一步类似,因为最大的盘子已经放到位,就可以看做其不存在,因为这个盘子始终不会移动了,而且别的盘子移动的时候因为这个盘子是最大的所以并不会因为它的存在而导致违背移动规则。这样的话,这一步又是一个递归的问题,每一次都可以看做一个问题规模减小1的过程。

汉诺塔代码:
#include<stdio.h>
 
int move(int n,char a,char b,char c)
{	
	static step_cnt = 0;

	if(n==1)
	{
        printf("\t%c->%c\n",a,c);    //当n只有1个的时候直接从a移动到c
		step_cnt ++;
	}
    else
    {
        move(n-1,a,c,b);            //n-1个要从a通过c移动到b
        printf("\t%c->%c\n",a,c);
		step_cnt ++;
        move(n-1,b,a,c);            //n-1个移动过来之后b变开始盘,b通过a移动到c
    }

	return step_cnt;
}
 
int main()
{
    int n, count;

    printf("请输入要移动的块数:");
    scanf("%d",&n);
    count = move(n,'a','b','c');
	printf("It needs %d steps in all.\n", count);
	
	return 0;
}

程序运行截图:

参考博文:http://blog.csdn.net/yangcaibin/article/details/1913945

                  http://www.cnblogs.com/ruofengzhishang/articles/1939444.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值