汉诺塔递归算法/搬金盘的婆罗门 - Python实现

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

17.1 汉诺塔问题

法国数学家爱德华·卢卡斯曾转述过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根金刚石柱。印度教的主神梵天在创造世界的时候,在其中一根石柱上从下到上的穿好了由大到小的64块金盘,这就是所谓的汉诺塔 - Hanoi Tower。

按照梵天的命令,不论白天黑夜,总有一个婆罗门僧侣在按照下面的规则移动这些金盘:一次只移动一个盘,不管在哪根柱上,小盘必须在大盘上面。僧侣们预言,当所有的金盘都从梵天穿好的那根柱上移到另外一根柱上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

17.1.1 求解

如下图所示的5个盘的汉诺塔问题,其总任务是将A柱上的n = 5个盘移至C柱。要实现这个总任务并且保证移盘过程中小盘始终在大盘上面,整个过程分三步实现。第1步:我们必须先将n - 1 = 4个黑盘从A柱移至B柱。在第1步的执行过程当中,为了保证规则的贯彻,显然,必须借助于C柱作为中转柱才能完成。

第1步所做的工作可描述为:借助中转柱C, 将n-1=4个盘从A移至B。

现在,最大的白盘在A柱上,C柱是空的。可实施第2步:将A柱上的大盘取下,移至C柱。

接下来,我们要做的是第3步: 借助中转柱A,将B柱上的n - 1 = 4个盘移至C柱。此时,C柱上虽然已经有了一个盘,但由于此盘是最大的,所以只要移动过程中不搬动C柱上的原有大盘,可以忽略其存在。

现在,我们试图总结一下总任务及其三个子任务:

总任务: 将 n = 5个盘从A柱移至C柱,以B柱为中转柱

不难看出,除了柱子不同,子任务3同子任务1所做的工作是一样的,都是把 n - 1 个盘从一个柱移至另一个柱。同时,子任务1,3与总任务之间也极其相似,除了需要移动的盘子数量差异外。

我们称,将n - 1个盘子从A移至B的汉诺塔问题,与原问题 - 即“将n个盘子从A移至C的汉诺塔问题”的性质完全相同,区别仅在于问题的规模 - 需要移动的盘子数量稍小。我也称为前者是原问题的子问题。

如果我们能将n - 1 = 4个盘子从A移至B,从B移至C,那么n = 5个盘子的汉诺塔问题可解。那么如何求解4个盘子的汉诺塔问题呢?聪明的读者已经有了答案。

子问题: 将 n’ = 4个盘从A柱移至B柱,以C柱为中转柱

下面的图展示了这一过程:


上面的分析可以看出,5盘汉诺塔问题可以通过求解4盘汉诺塔问题来解决,4盘汉诺塔问题可以通过求解3盘汉诺塔问题来解决。同理,3盘汉诺塔问题可以通过求解2盘汉诺塔问题来解决,2盘汉诺塔问题可以通过求解一盘汉诺塔问题来解决。而一盘汉诺塔问题,由于问题的规模足够小,可直接解决:把盘从原柱搬至目标柱即可。所以在前表中,我们称其为“简单任务”。

17.1.2 递归算法

根据前一小节描述的算法思想,我们可以写出汉诺塔问题求解的递归算法。

#BasicHanoi.py
def hanoi(n, a, b, c):if n == 1:movements.append(a + " --> " + c)else:hanoi(n - 1, a, c, b)movements.append(a + " --> " + c)hanoi(n - 1, b, a, c)movements = []
hanoi(5, 'A', 'B', 'C')
print("Steps count:",len(movements))
print("The first 3 steps are:", movements[:3])

函数hanoi(n,a,b,c)用于生成以b为中转柱,将n个金盘从a移至c的移盘序列。可以看到,这个递归函数的执行过程跟前节的总任务-子任务分解完全一致。当n == 1时,只有一个盘子,简单任务,直接移盘。如果n > 1,则分解为两个 n - 1 的汉诺塔子问题,以及一个简单移盘任务。子问题的求解以函数递归调用来解决。

上述代码的执行结果如下:

Steps count: 31
The first 3 steps are: ['A --> C', 'A --> B', 'C --> B']

上述结果表明,5盘汉诺塔问题共需要31次移盘。movements列表中按顺序存储了全部的移盘动作。

17.1.3 计算复杂性

使用前小节中的程序,作者尝试计算了n = 5 … 12汉诺塔问题的移盘过程,得到下述移盘次数。

看起来,似乎n个盘的汉诺塔问题的移盘次数为2n-1。事实上,对移盘次数的数学分析可以证明这个结论。n盘的汉诺塔求解可以拆分成两个n-1盘的汉诺塔求解再加上1次简单移盘。如果用T(n)来表示n盘汉诺塔的移盘次数的话,函数T(n)可使用下述递归定义。

我们试着把递归函数消解成非递归函数。

令t = n - 1,有:

故n盘汉诺塔共需移盘2n-1次。那么,如果梵天规定的是64个金盘的话,总移动次数则为264-1 = 18446744073709551615。如果婆罗门僧侣是个熟练工,1秒挪一个盘,那么1小时可以移3600个盘,1年可移3600 x 24 x 365 = 31536000个盘(忽略闰年误差)。那么,解64盘汉诺塔问题共需要(264-1)/31536000年,即大约5949亿年。看起来,按照当前的人类知识,印度的古老智慧好像高估了地球的预期寿命。

读者不要去尝试计算hanoi(64,’A’,’B’,’C’),显然,在你有限的人生里,是无法完成这件接近“无限”的大事的。而且,因为递归所导致的内存消耗,你有限的计算机内存也排除了这种可能性。

作者是无神论者,上述探讨基于严谨的数学,作者不相信任何人格化的“上帝 ”。

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++

Python编程基础及应用

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程

汉诺塔递归算法/搬金盘的婆罗门 - Python实现相关推荐

  1. python汉诺塔_汉诺塔递归算法/搬金盘的婆罗门 - Python实现

    汉诺塔递归算法/搬金盘的婆罗门 - Python实现 版权声明 本文节选自作者本人的图书<Python编程基础及应用>,高等教育出版社.本文可以在互联网上自由转载,但必须:注明出处(作者: ...

  2. 汉诺塔递归算法进阶_进阶python 1递归

    汉诺塔递归算法进阶 When something is specified in terms of itself, it is called recursion. The recursion give ...

  3. python汉诺塔递归算法_Python文摘:汉诺塔问题与递归算法

    历史传说: 在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑夜 ...

  4. 汉诺塔-递归算法深入理解

    汉诺塔算法就3个步骤: 第一,把a上的n-1个盘通过c移动到b: 第二,把a上的最下面的盘移到c: 第三,因为n-1个盘全在b上了. 所以把b当做a重复以上步骤就好了.不过,思考过程还是很痛苦的,难以 ...

  5. python汉诺塔递归算法流程图_python实现汉诺塔的图解递归算法

    一.起源: 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小 ...

  6. python汉诺塔递归算法流程图_详解汉诺塔Python递归程序

    学习递归时,很多小伙伴对汉诺塔的递归算法非常疑惑,不清楚那么复杂的移动过程,为何用四五行代码就给解决了.汉诺塔问题:有三根柱子A,B,C.A柱上有若干碟子,每次移动一块碟子,小的只能叠在大的上面,把所 ...

  7. python汉诺塔递归编程_python中的汉诺塔递归算法的具体运算过程是怎样的?

    关键点:不要多想,不要像人类一样整体来看,盲人摸象即可. 以最开始提出此猜想的 [传说越南河内某间寺院有三根银棒,上串 64 个金盘] 为例. 三根银棒我们设为A,B,C. 欲将A棒上的64个金盘移动 ...

  8. 对汉诺塔递归算法的理解(图解,附完整代码实现)

    前情提要: 首先说一下汉诺塔游戏的规则:如下图所示,有三个柱子A,B,C,我们要做的是把A柱的所有圆盘,全部转移到C柱上,转移时遵循的规则如下: 1.每次只能移动一个圆盘 2.所有的大圆盘必须在小圆盘 ...

  9. python汉诺塔递归算法流程图,python实现汉诺塔递归算法经典案例

    Python汉诺塔递归问题 python请用递归算法编程解决汉诺塔问题 在线等 关于python递归函数实现汉诺塔 def move(n,a,b,c): #1 if n==1: #2 print(a, ...

最新文章

  1. 终于知道移动比联通牛的原因了(绝对真实绝对有趣)不看后悔
  2. php邮件通知,邮件通知设置
  3. 排序陷阱 List.Sort Linq.OrderBy
  4. 快速数论变换(NTT)
  5. android titlebar 高度是多少,什么是TitleBar的默认高度和Android中Titlebar中的默认TextSize?...
  6. System.IO.Ports.SerialPort串口通信接收完整数据
  7. 文本在线查重系统的设计与实现(毕业设计)
  8. 三星s10刷android原生,【极光ROM】-【三星S10E/S10/S10+ G97XX-9820】-【V12.0 Android-Q-TD1】...
  9. PHP语言面对对象编程之继承
  10. activiti学习之排他网关
  11. 如何为您的Android手机创建自定义铃声
  12. 三角波发生器电路图分析
  13. 尾部关性尾部风险平价和圣杯分布
  14. 国内外php主流开源cms汇总(2010年1月) .
  15. linux docker安装nginx且测试elasticsearch分词
  16. Arcpy的制图模块
  17. JS禁止浏览器打开控制台或查看源代码
  18. win7进不了系统怎么办
  19. 磁吸充电宝CE认证介绍
  20. 如何创建你的SOLIDWORKS ID?

热门文章

  1. 车辆数字钥匙ICCE标准和CCC标准的简单分析和比较
  2. 小说中看到的一些有意思的句子
  3. [FPGA 学习记录] FPGA 开发环境的搭建
  4. css animation顺序,按顺序运行css动画和WebkitAnimationEnded
  5. 介绍各种压缩格式MPEG1--MPEG4--MPEG7—MPEG21-H.264
  6. HTTP协议,HTTPS协议,SSL/TLS协议概述
  7. BZOJ2085 : [Poi2010]Hamsters
  8. NOIP2011计算系数详解
  9. Fibonacci数列 递归与分治
  10. C#线程池ThreadPool.QueueUserWorkItem接收线程执行的方法返回值