算法:汉诺塔问题(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完全可以满足一般情况 ...
随机推荐
- git config 选项
git config --global -- global 写入选项:写入全局的 ~/.gitconfig 文件而不是版本库的 .git/config,如果 ~/.gitconfig 文件不存在,则 ...
- 基于React和GraphQL的黛梦设计与实现
写在前面 这是笔者在中秋无聊写着玩的,假期闲暇之余憋出来的帖子.麻雀虽小,但五脏俱全,涉及到的方方面面还是蛮全的.所以就设计了一个黛梦(demo)------ 打通了GraphQL的接口与前端交互的流 ...
- 学习PHP中国际化地数字格式处理
不知道大家有没有了解过,对于数字格式来说,西方国家会以三位为一个进位,使用逗号来分隔.比如,12345678,用标准的格式来表示的话就是 12,345,678 .不过我们中文其实并不会有这样的分隔符, ...
- js相同的正则多次调用test()返回的值却不同的问题
js代码: var name = '测试中文';// 姓名 var nameRgexp = new RegExp("[a-zA-Z\u4e00-\u9fa5]{2,}"," ...
- html阴影 box-shadow
右下阴影 div { box-shadow: 10px 10px 5px #888888; }四周阴影 div { box-shadow: 0 0 5px #888888; } div {box-sh ...
- Mysql Navicate 基础操作与SQL语句 版本5.7.29
SQL数据的增删改查:此部分所有SQL语句在navicat中与mysql命令行执行效果一样,只是mysql服务端在命令行执行,而navicat只是在客户端的图形化打开操作. 一.进入数据库 .连接数据 ...
- Appium driver常用API
click driver.find_element implicitly_wait send_keys close quit get_window_size switch_to execute bac ...
- 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 百篇博客分析OpenHarmony源码 | v30.02
百篇博客系列篇.本篇为: v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当 ...
- P5631-最小mex生成树【线段树,并查集】
正题 题目链接:https://www.luogu.com.cn/problem/P5631 题目大意 \(n\)个点\(m\)条边的一张图,求\(mex\)值最小的一棵生成树. 解题思路 考虑比较暴 ...
- golang引用第三方包的报错:no required module provides package [完美解决]
关于golang第三方包的引用报错:no required module provides package : go.mod file not found in current directory o ...