拿捏汉诺塔问题(附有动图)

简介: 相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

一、故事背景



相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。


二、简化问题



  1. 把 A 杆上的所有盘子放在 C 杆上


  1. 规则是:


(1)盘子可以被随意移动到别的杆,但一次只能移动一个盘子
(2)最终在 C 杆上呈现的结果是:小盘在上,大盘在下


三、建立模型(动态图)



  1. 一个圈圈


image.gif


  1. 两个圈圈


image.gif


  1. 三个圈圈


090beaef771346e48adc0c2a10aa3b10.gif


  1. 四个圈圈


1217b3077db9467391e3c8461e53f64d.gif


四、代码实现



程序清单:


public class test {
    public static void main(String[] args) {
        Hanoi(1, 'A', 'B', 'C');
        System.out.println();
        Hanoi(2, 'A', 'B', 'C');
        System.out.println();
        Hanoi(3, 'A', 'B', 'C');
        System.out.println();
        Hanoi(4, 'A', 'B', 'C');
        System.out.println();
    }
    public static void Hanoi(int n, char A, char B, char C) {
        if (n == 1) {
            move(A, C);
        } else {
            Hanoi(n - 1, A, C, B);
            move(A, C);
            Hanoi(n - 1, B, A, C);
        }
    }
    public static void move(char pos1, char pos2) {
        System.out.print(pos1 + "->" + pos2 + "  ");
    }
}


输出结果:


45a24ec219e5430ba84149a780c79b52.png


五、代码分析



  1. 主函数写了四种情况,分别对应 1 - 4 个盘子
  2. move 函数表示每一次盘子从一个位置移动到另一个位置
  3. Hanoi 函数是核心,它呈现了递归思想
  4. Hanoi 函数中 if (n == 1) 这一行代码就是终止条件,而下面对应的 else 就是规律公式,用来无限趋近于这个终止条件的,当达到这个终止条件时,那么就层层返回!也就是开始递归中的 “ 归 ”!


接下来,就Hanoi 函数,我们进行分析


当 n = 1 时,也就是说此时只有一个盘子,那么只需要移动一次,直接把它放到 C 杆上就行了。


当 n = 2 时,此时有两个盘子,那么我们先得把两个圈圈中最小的圈圈从 A 杆移动到 B 杆,过渡一下,然后才能把最大的圈圈放在 C 杆上,从而实现最终目的,也就是说,此时的B杆充当了中介。


当 n = 3 时,…

当 n = 4 时,…


上面我就不再赘述了,所以我们找到了规律:


不论几个盘子,B杆始终充当了中介杆,而此时,不论怎么移动,肯定出现了这种情况:C杆已经放置了最大的那个盘子,B杆上放的是除了那个最大盘子之外的所有盘子。


如下:


n = 3 时

此时 B 杆上的盘子个数为 n - 1 = 2


image.jpeg


n = 4时

此时 B 杆上的盘子个数为 n - 1 = 3


image.jpeg


当盘子很多很多时,假设就为n


image.jpeg


此时B杆上的盘子个数为 n - 1

那么我们就把这 n - 1 个盘子想象成一个整体,直接就挪到C杆上,但是我们不关心这其中有多少步骤,不关心这些步骤又是怎么算的,因为我们可以把这个计算步骤交给计算机去算,作为程序员,我们只要设置程序让他跑就行了。


image.jpeg


所以,请注意!!!


现在我们回过头看程序清单中 Hanoi 函数,我们就不迷糊了,请看图:

当 n >= 2 时,我们先把 n - 1 个盘子先从 A 挪到 B,再从 B 挪到 C,在这个过程中,我们要有整体的思想


我们要思考的是:在某一个过程,哪些盘子充当整体?哪个杆又充当中介?


image.png


很多人的思想总是停留在一个一个盘子的挪,这种思想是非常复杂的,甚至这样想问题的出发点就是错的!因为你找不到规律不说,在盘子的数量为4个以上时,你很可能会移错步骤,一步错,那么步步错!


你可以看到我在上面的动态图演示的时候,那已经是最完美的情况了,在不会移错的情况下都那么复杂,何况移错的情况下呢?


总结



  1. 经典的汉诺塔问题在计算机中,包含了递归思想,这就要回到递归的本质,通过找到规律,从而大事化小,得出结果。


  1. 前两个博客介绍了递归的思想和例子,这篇博客用来结尾基础部分的递归,后面等学到算法的时候,再回过头看,或许思路会更加清晰。


fa3e2c5611e5421fad5d8eadbb0f8abf.jpg


Over. 谢谢观看哟~


目录
相关文章
|
4月前
|
算法
算法刷题(二十二):宝石与石头
算法刷题(二十二):宝石与石头
39 0
|
4月前
|
算法 vr&ar 图形学
☆打卡算法☆LeetCode 218. 天际线问题 算法解析
☆打卡算法☆LeetCode 218. 天际线问题 算法解析
|
6月前
代码随想录Day27贪心02 下 LeetCodeT45 跳跃游戏II
代码随想录Day27贪心02 下 LeetCodeT45 跳跃游戏II
19 0
|
5天前
|
算法
代码随想录算法训练营第六十天 | LeetCode 84. 柱状图中最大的矩形
代码随想录算法训练营第六十天 | LeetCode 84. 柱状图中最大的矩形
18 3
|
4月前
|
算法 vr&ar 图形学
☆打卡算法☆LeetCode 174. 地下城游戏 算法解析
☆打卡算法☆LeetCode 174. 地下城游戏 算法解析
|
5月前
|
算法 测试技术 容器
代码随想录算法训练营第四十二天 | LeetCode 1049. 最后一块石头的重量 II、494. 目标和、474. 一和零
代码随想录算法训练营第四十二天 | LeetCode 1049. 最后一块石头的重量 II、494. 目标和、474. 一和零
28 1
|
7月前
|
C++
蓝桥杯 2240. 买钢笔和铅笔的方案数c++解法
蓝桥杯 2240. 买钢笔和铅笔的方案数c++解法
71 0
|
9月前
一段动态规划代码赏析
输入一个字符串 和 一个pattern. 返回结果是否匹配上
28 0
|
10月前
|
机器学习/深度学习 存储 算法
代码随想录训练营day30| 332.重新安排行程 51. N皇后 37. 解数独
代码随想录训练营day30| 332.重新安排行程 51. N皇后 37. 解数独
|
11月前
|
算法 C语言 C++
算法修炼之练气篇——练气二十一层
每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的,练完这200多道题就考了今年第十四届的B组蓝桥杯C/C++获得了省一,后面还会更新“算法修炼之筑基篇”里面包括了省赛到国赛这一个月训练的刷奖计划,大概有40道左右,感兴趣的话可以关注一下命运之光)
145 0
算法修炼之练气篇——练气二十一层