C#之汉诺塔(河内塔)递归问题


前言

小时候在直板手机上玩过这么一款叫做“汉诺塔”的游戏,游戏方式很简单,通过上下左右四个按键将一堆大小有序、垂直排列的圆盘从一根柱子上移动到另一根柱子上,小时候也懒得思考就是在瞎玩。现在用递归的思想来解决一下这个问题,我尽可能把我自己的理解方式通俗的讲给大家,如有不对的地方,请大家批评指正!

一、汉诺塔问题

我们就依照这个图上所说的64个圆片来解决问题(图片出处:刘铁猛老师)
在这里插入图片描述

二、问题思考

1.简单定义一下

这里为了表达更清楚,我们定义一下:
三根柱子分别为A柱,B柱,C柱。
Px代表柱上的圆片,P1代表从上至下第一个圆片(也就是最小的那个圆片),同理,P64代表从上至下最后一个圆片(也就是最大的那个圆片)。
Nm~n代表把Pm与Pn(包括Pm和Pn本身)之间所有的圆片移动到另外一根柱子上所用的次数。
例如,N1~63代表把P1与P63(包括P1和P63本身)之间所有的圆片移动到另一根柱子上所用的次数。

2.假设简单的情况

这里我们先来假设一种比较简单的情况,如图,三根柱子(A,B,C),3个圆盘,P1,P2,P3
在这里插入图片描述

那么我们思考一下,想把全部的圆盘移动到另外一根柱子上需要怎么做?
首先:把P1和P2移动到C柱上,这样做的目的是为了把P3暴露出来以便可以移动(这里先不管具体操作了多少步,而是从整体上考虑应该怎么做)
在这里插入图片描述

其次:把P3移动到B柱上
在这里插入图片描述

最后:把P1和P2移动到B柱上
在这里插入图片描述

至此,我们一共做个3件事情:
1.把除了最大圆盘以外的其余圆盘从A柱移动到C柱(即:把P1和P2从A柱移动到C柱)
2.把最大圆盘从A柱移动到B柱(即:把P3从A柱移动到B柱)
3.把除了最大圆盘以外的其余圆盘从C柱移回到B柱(即:把P1和P2从C柱移动到B柱)

到这里我们应该能发现两个比较重要的问题:
(1)如果我们把除最大圆盘以外的其他圆盘看作一个整体,那么这个整体被移动了两回(从A柱到C柱,从C柱到B柱),我们假设这个整体被移动一回所需要的次数为N
(2)当(1)中的整体被移动以后,所暴露出来最大的那个圆盘,只需要移动一次(从A柱到C柱)

so,我们完成整个流程所需要的次数是N+1+N(移动整体+移动最大的+移动整体)。
but,这个整体怎么办呢?这个整体就接着用这个方法再去解决,一层一层的,这就是递归的思想啦,我们接下来用题目的例子详细讲一下

3.推广

现在我们来看题目中的问题,64个圆盘,3根柱子
在这里插入图片描述
依照我们之前的思想,现在我们解决N1~64(即:整体移动P1至P64所需次数)
  (1.1)把P1至P63看作一个整体,移动到另外一个柱子上,所需次数为N1~63
  (1.2)接着移动P64,所需次数为1次
  (1.3)把P1至P63移动回来,所需次数为N1~63
  (1.4)N1~64 = N1~63 + 1 + N1~63
       N1~63怎么算?(即:整体移动P1至P63所需次数)
     (2.1)把P1至P62看作一个整体,移动到另外一个柱子上,所需次数为N1~62
     (2.2)接着移动P63,所需次数为1次
     (2.3)把P1至P62移动回来,所需次数为N1~62
     (2.4)N1~63 = N1~62 + 1 + N1~62
        N1~62怎么算?(即:整体移动P1至P62所需次数)
        ·
        ·(…此处省略中间的步骤…)
        ·
          N1~2怎么算?(即:整体移动P1至P2所需次数)
        (63.1)把P1看作一个整体,移动到另外一个柱子上,所需次数为N1
        (63.2)接着移动P2,所需次数为1次
        (63.3)把P1移动回来,所需次数为N1
        (63.4)N1~2 = N1 + 1 + N1
             N1怎么算?(即:整体移动P1所需次数)
           (64.1)N1就很简单了,那当然就是1啦!
           (64.2)N1~2 = N1 + 1 + N1

4.核心代码

        public int Hanoi(int num)//参数num代表圆盘数
        {
            if(num == 1)
            {
                return 1;
            }
            else
            {
                //特别提醒:下面的result用的是int类型,如果参数num输入的是题目中的64,得到的结果是不正确的,因为已经超过了int类型的最大值,因此,需要变为long型或者double型来接收结果或者将参数num减小
                
                //1和2方法都可以,但2似乎更快?
                //1.
                int result = Hanoi(num - 1)  + 1 + Hanoi(num - 1);
                //2.
                int result = Hanoi(num - 1)*2 + 1;
                return result;
            }
            
        }

总结

本文简单介绍了递归思想在汉诺塔问题中的应用,文笔有限,若文章中有不当之处,还望各位批评指正!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值