汉诺塔Python递归

 

汉诺塔 问题是源于印度一个古老传说。

在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石柱子。印度教的主神梵天在创造世界的时候,在其中一根柱子从下到上穿好了由大到小的64片金圆盘,不论白天黑夜,总有一个僧侣在移动这些金盘。

规则:

将一根柱子上的所有圆盘都移动到另一个柱子上,并且还是按照顺序堆放,底部最大,顶部最小,且每次只能移动一个,大圆盘不能压在小圆盘上面!

僧侣们预言,当所有的金盘都从梵天穿好的那根柱子上移到另外一根柱子上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽!

敲重点!当64个圆盘都移动完毕的时候,世界将会毁灭。。。e

先来看张图,将a柱子上的圆盘,借助柱子b,最终全部都移动到c

模型图 : 左边为初始状态  右边为完成状态
动图展示

 

用python程序来列出移动圆盘的步骤 (可先看底部代码)

首先考虑就是用递归来求解,虽然递归不是最好的程序算法,但它很容易理解,适合在这个问题上。我们先想一想,要把A上面的圆盘全部移动到C,最后在C上面也是排好顺序的,那么A柱子最下面的那个大圆盘,一定要先到C柱子,然后其余圆盘才能往它身上放。而要想移动最底下的大圆盘,必须把它上面的全部圆盘都移动到B,然后才可以把最大的圆盘移动到C。

当圆盘只有3个的时候,从上到下,分别为1,2,3号,3号盘子要去C柱子,所以会对2号盘子说:你们都去B,这样我就可以去C了,2号盘子听了,刚想移动,发现自己身上压了1号盘子,然后对1号盘子说:我们都要去柱子B,但是你得先挪到C,我才能去B,1号柱子听了,然后就很不情愿的挪到了C......

设圆盘个数有n个,那最大圆盘上面的个数就是n-1。

第一步:先把n-1个圆盘从A移动到柱子B。此时你可能有疑问了,不是说每次只能移动一个圆盘吗?怎么一下直接移动了n-1个柱子呢?(这里就是用到了递归,例如你用递归统计目录下所有文件的大小,它并不能直接一步计算大小,而是对目录进行遍历,是文件就计算大小,是目录就继续遍历,直到找完了所有的文件,再返回相加,最终得到总的文件大小)

汉诺塔递归的三步,就类似把大象装冰箱,打开冰箱,把大象塞进去,再关上冰箱。你并不需要清楚大象是怎么塞进冰箱的,你只需要知道整体流程步骤。

接着第二步:n-1个盘子都移动到了柱子B,那第二步就是把剩下的1个大圆盘移动到柱子C 现在最大的圆盘已经到了柱子C了,那么还剩下n-1个圆盘需要移动,此时n-1个圆盘还在柱子B上。

第三步:现在柱子B上面有n-1个柱子,A柱子是空的,所以只能借助A,将圆盘从B移动到C,而此时你会发现,A借助B,移动到C,和B借助A,移动到C,是一样的。即柱子B上面剩下的n-1个圆盘,要想移动最底下的那个,得把上面所有的圆盘(n-2个)移动到A,这样最底下的那个圆盘就能移动到柱子C了。(理解其实第三步就是又回到第一步)

柱子A,B换位置

用代码表示如下:

def move(n,a,b,c):
    if n == 1:      #递归的收敛条件,当n为1,时,执行移动的操作
        print('move:',a,'-->',c)   #打印 move 为字符串,a和c是参数
        return
    move(n-1,a,c,b)    #先把n-1个盘子,从a移动到b
    move(1,a,b,c)      #再将剩下的1个盘子,从a移动到c
    move(n-1,b,a,c)    #柱子b上面有n-1个盘子,再将盘子从b,借助a,移动到c
 
move(3,'A','B','C')    #给定盘子数n=3,a,b,c分别叫A,B,C

 结果:

递归函数打印出了移动盘子的步骤

move: A --> C
move: A --> B
move: C --> B
move: A --> C
move: B --> A
move: B --> C
move: A --> C

汉诺塔盘子数量n,和移动的总共步数y的关系为:y = 2^n - 1

计算一下移动64个盘子所需的步数 :y = 2^(64) -1 = 18446744073709551615

假设那个僧侣每天不睡不停地 1秒钟移动一个圆盘

那么移动64个圆盘所需的时间年限就是:18446744073709551615 \div 86400 \div 365 =584942417355年

5849亿年!!!

而地球的年龄至今也才45亿年。

 

  • 25
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值