算法:汉诺塔问题(Tower of Brahma puzzle)
一、算法背景
最早发明这个问题的人是法国数学家爱德华·卢卡斯。传说越南河内某间寺院有三根银棒(A, B, C),上串 64 个金盘。 寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。 这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。但不知道是卢卡斯自创的这个传说,还是他受他人启发。

A C B
二、汉诺塔算法
有三根杆子A,B,C。A 杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
- 每次只能移动一个圆盘;
- 大盘不能叠在小盘上面。
提示:可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
问:如何移?最少要移动多少次?
解法的基本思想是递归。假设有 A、B、C 三个塔,A 塔有 块盘,目标是把这些盘全部移到 C 塔。那么先把 A 塔顶部的
块盘移动到 B 塔,再把 A 塔剩下的大盘移到 C,最后把 B 塔的
块盘移到 C。如此递归地使用下去, 就可以求解。
1 /**
2 * Java递归函数解决河内塔之难题
3 *
4 * @param n 移动物体数量
5 * @param fromRod 原先放的位置
6 * @param toRod 要放去的位置
7 * @param auxRod 中间留空方便转移的位置
8 */
9 private static void towerOfHanoi(int n, char fromRod, char toRod, char auxRod) {
10 count++;
11 if (n == 1) { // 递归出口
12 System.out.println("Move disk 1 from rod " + fromRod + " to rod " + toRod);
13 return;
14 }
15 towerOfHanoi(n-1, fromRod, auxRod, toRod);
16 System.out.println("Move disk " + n + " from rod " + fromRod + " to rod " + toRod); // 移动
17 towerOfHanoi(n-1, auxRod, toRod, fromRod);
18 }
设移动 n 个盘子的汉诺塔问题需要 towerOfHanoi(n) 次移动操作来完成。由展示移动过程算法可知 towerOfHanoi(n) 应是三部分之和。
(1) 将 n 个盘上面的 n-1 个盘子借助 C 桩从 A 桩移到 B 桩上,需 towerOfHanoi(n-1) 次移动;
(2) 然后将 A 桩上第 n 个盘子移到 C 桩上(1次);
(3) 最后,将 B 桩上的 n-1 个盘子借助 A 桩移到 C 桩上,需 towerOfHanoi(n-1)次。
因而有递归关系: towerOfHanoi(n) = 2 * towerOfHanoi(n-1) + 1,初始条件(递归出口): towerOfHanoi(1) = 1,即 1、3、7、15、31…… 移动次数 count = towerOfHanoi(n) = 2n -1 ,时间复杂度为 O(2n)。
本文源代码:
1 package algorithm;
2
3 /**
4 * 汉诺塔问题(Tower of Brahma puzzle)
5 *
6 * 最早发明这个问题的人是法国数学家爱德华·卢卡斯。
7 *
8 * 传说越南河内某间寺院有三根银棒,上串 64 个金盘。
9 * 寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。
10 * 这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。
11 * 但不知道是卢卡斯自创的这个传说,还是他受他人启发。
12 *
13 * 若传说属实,僧侣们需要 2^{64}-1 步才能完成这个任务;
14 * 若他们每秒可完成一个盘子的移动,就需要 5849 亿年才能完成。整个宇宙现在也不过 137 亿年。
15 *
16 * 这个传说有若干变体:寺院换成修道院、僧侣换成修士等等。
17 * 寺院的地点众说纷纭,其中一说是位于越南的河内,所以被命名为“河内塔”。
18 * 另外亦有“金盘是创世时所造”、“僧侣们每天移动一盘”之类的背景设定。
19 */
20 public class TowerOfHanoi {
21 /* 移动次数 */
22 private static int count = 0;
23
24 /**
25 * Java递归函数解决河内塔之难题
26 *
27 * @param n 移动物体数量
28 * @param fromRod 原先放的位置
29 * @param toRod 要放去的位置
30 * @param auxRod 中间留空方便转移的位置
31 */
32 private static void towerOfHanoi(int n, char fromRod, char toRod, char auxRod) {
33 count++;
34 if (n == 1) {
35 System.out.println("Move disk 1 from rod " + fromRod + " to rod " + toRod);
36 return;
37 }
38 towerOfHanoi(n-1, fromRod, auxRod, toRod);
39 System.out.println("Move disk " + n + " from rod " + fromRod + " to rod " + toRod);
40 towerOfHanoi(n-1, auxRod, toRod, fromRod);
41 }
42
43 public static void main(String[] args) {
44 int n = 4;
45 towerOfHanoi(n, 'A', 'C', 'B');
46 /**
47 * 可见移动次数是 (2^n-1), 其时间复杂度O(2^n)。
48 *
49 * 一天24h, 一小时60min, 一分钟60s, 一天有 24*60*60 = 86400(s), 一年平均365天来算,一年有 3153,6000 (s)
50 * 可见要几千亿年才能移动完, 这个算法用于移动大数量小空间的物体肯定是行不通的。
51 *
52 * 这个算法主要考验人的解决问题、逻辑思想, 以及计算推理的能力
53 */
54 System.out.println("移动次数:" + count);
55 }
56 }
算法:汉诺塔问题(Tower of Brahma puzzle)的更多相关文章
- 汉诺塔 Hanoi Tower
电影<猩球崛起>刚开始的时候,年轻的Caesar在玩一种很有意思的游戏,就是汉诺塔...... 汉诺塔源自一个古老的印度传说:在世界的中心贝拿勒斯的圣庙里,一块黄铜板上插着三支宝石针.印度 ...
- python算法-汉诺塔问题
汉诺塔问题 初始状态: 思考:当盘子的个数是3的时候,大家写出移动顺序 移动的步骤: 3个盘子,从a到c 1.前面两个盘子,从a到b 1)把前面一个盘子,从a到c a->c 2)把第二个盘子 ...
- C++汉诺塔递归实现
程序背景: 汉诺塔(Tower of Hanoi)又称河内塔,问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命 ...
- 汉诺塔(河内塔)算法 ----C语言递归实现
汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子, 在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺 ...
- 汉诺塔算法详解之C++
汉诺塔: 有三根杆子A,B,C.A杆上有N个(N>1)穿孔圆环,盘的尺寸由下到上依次变小.要求按下列规则将所有圆盘移至C杆: 每次只能移动一个圆盘: 大盘不能叠在小盘上面. 提示:可将圆盘临时置 ...
- 汉诺塔算法的递归与非递归的C以及C++源代码
汉诺塔(又称河内塔)问题其实是印度的一个古老的传说. 开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一 个小, ...
- [js - 算法可视化] 汉诺塔(Hanoi)演示程序
前段时间偶然看到有个日本人很早之前写了js的多种排序程序,使用js+html实现的排序动画,效果非常好. 受此启发,我决定写几个js的算法动画,第一个就用汉诺塔. 演示地址:http://tut.ap ...
- C语言之算法初步(汉诺塔--递归算法)
个人觉得汉诺塔这个递归算法比电子老鼠的难了一些,不过一旦理解了也还是可以的,其实网上也有很多代码,可以直接参考.记得大一开始时就做过汉诺塔的习题,但是那时代码写得很长很长,也是不理解递归的结果.现在想 ...
- what' the python之递归函数、二分算法与汉诺塔游戏
what's the 递归? 递归函数的定义:在函数里可以再调用函数,如果这个调用的函数是函数本身,那么就形成了一个递归函数. 递归的最大深度为997,这个是程序强制定义的,997完全可以满足一般情况 ...
随机推荐
- jsPlumb开发流程设计器
前言 jsPlumb是一款开源软件,但jsPlumb toolkit是收费的. 本文主要使用jsPlumb实现一些简单的流程设计功能. 基础学习 首先引入jsplumb.min.js. <scr ...
- freeswitch 编译安装后的配置
--------------------FreeSWITCH configuration------------Locations: prefix: /usr/local/freeswitchexec ...
- FastAPI(4)- get 请求 - 路径参数 Path Parameters
什么是路径 假设一个 url 是: http://127.0.0.1:8080/items/abcd 那么路径 path 就是 /items/abcd 路径参数 就是将路径上的某一部分变成参数,可通过 ...
- Django学习day15BBS项目开发2.0
每日测验 """ 今日日考 1.img标签src属性可以指代的值有哪些,各有什么特点 2.pillow模块是干什么用的,主要的方法有哪些 3.简述登陆功能图片验证码相关逻 ...
- Jmeter扩展组件开发(6) - 将响应结果数据显示到查看结果树中
CODE //用来存储响应数据,目的是将响应结果放到查看结果树当中private String resultData;/** 这个方法就是实现你具体功能逻辑的方法* @param javaSample ...
- Groovy系列(4)- Groovy集合操作
Groovy集合操作 Lists List 字面值 您可以按如下所示创建列表. 请注意,[]是空列表表达式 def list = [5, 6, 7, 8] assert list.get(2) == ...
- YOLO v3 & Pascal VOC数据集
代码地址:https://github.com/YunYang1994/tensorflow-yolov3 https://hackernoon.com/understanding-yolo-f5a7 ...
- javascript 自定义事件 发布-订阅 模式 Event
* javascript自定义事件 var myEvent = document.createEvent("Event"); myEvent.initEvent("myE ...
- css 样式设定
阴影: --可以同时设定多个阴影.用逗号隔开 http://www.fly63.com/article/detial/4726 div { box-shadow: 10px 10px 5px #888 ...
- Python3入门系列之-----算术运算符|比较运算符|赋值运算符|逻辑运算符|成员运算符|身份运算符
什么是运算符? 本章节主要说明Python的运算符.举个简单的例子 1 +2 = 3 . 例子中,1 和 1.2 被称为操作数,"+" 称为运算符. Python语言支持以下类型的 ...