汉诺塔细讲(内含邻近,循环。以及作者对汉诺塔,以及分治算法的小感悟,注释)
小伙伴们大家好,今天是我第一次尝试去发文写作,有不好之处请多多包含。
什么是汉诺塔呢?
其实大家已经很熟悉他了(而且这是我的第一个递归题目)
注意:本章统一是将从第一根柱子转移到第三根柱子
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
这是百度上的答案。
那我们今天要解决的问题也很简单,就是把那个64换成任意数,并求出,我们搬运的次数以及路径(有游戏当然也要写出攻略嘛)
假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。(这个就相当于小学里的找规律嘛)。
最常规的方法是啥?当然是递归喽(java版本)
(统一说明一下这里的n是有几个圆盘)
package hannuota;public class taxt {public static void main(String[] args) { System.out.println(f(3));}static int f(int n){ // 递归停止代码if(n==0){return 0;}else { // 为什么是+1,而不是-1;(作者建议你把n=1带进去想) // 而且我们都知道递归的规律是什么?/**所谓递归就是(自己调用自己)*当代码再向下的的规程中,突然碰到自己调用自己的情况(你可以想象成盗梦空间)*然后进去下一个梦境(就是代码从头开始运行)* 而结束点就是盗梦空间的最后一层空间。* 当到达最后空间的时候直接返回开始继续上一层没进行完成的梦(没运行完的代码)* 做完这一层的梦(运行完这一次代码)就有开始返回上一层空间* 。。。。。。* 无限返回,直到返回现实(最初的代码)**/return 2*f(n-1)+1;}} }
那肯定还有想问作者还有其他方法吗?
有,还不止一种。
既然发现规律为什么不去用呢?
static int c(int n){ // 这是汉诺塔只有一个时候的int z=1;for(int i=1;i<n;i++){ // 为什么i=1;因为z已经等于1了啊,我们已经直接将n=1带入了z=z*2+1;}return z;} }
那还有一种方法是啥?
各位观众老爷别急啊,最后一种方法是跟攻略一起来的
当然最后一种的方法比较难。已经是属于算法的系列(分治算法)
(新手看不懂很正常,不要勉强自己,强行去看,脑子会难受的)
package hannuota2;public class text { // 解释一下为什么会在这初始化v/*上文我们刚刚讲到递归时,递归是相当于盗梦空间盗梦空间梦境都是基本相同,当进入下一个空间是它又是一个新的开始就好像一个不停循环的时间,一切都跟往常一样,除了你(你带进去的数,这就是变量)当我们在函数里初始化v时,当进入下一层梦境里时(v又被初始化为0),无法作为计数器去帮我们统计所以我们可以设置一个全局变量作为计数器*/static int v=0;public static void main(String[] args) {int a=1,b= 2,c=3;d(a,b,c,3);System.out.println(v);}static void d(int a,int b,int c,int n){ //而不是在这里,移步上方if(n==1){System.out.println("第"+n+"个棋子从"+a+"到"+c);v++;}else {d(a,c,b,n-1);System.out.println("第"+n+"个棋子从"+a+"到"+c);v++;d(b,a,c,n-1);}} }
在这里我先不细讲这个代码,等下把另外两个(攻略)写出来一起讲
(就比较容易看一点)
邻近汉诺塔又是什么呢(我觉得是那个大汉闲了没事故意找麻烦的)
(大家可以在离散数学实验中找一下,啥?没学到,先收藏,等学到再刚回来看,千万不要忘了啊)
所谓“临近移动” 就是在原始的汉诺塔问题上增加一个要求:不允许A柱与C柱之间的直接转移,即每次只能移动到中间柱B或从中间柱B移出(如下图所示)。
(啥,为啥上文没有配图?因为就很任意,没这么麻烦)
static void l(int a, int b, int c, int n) {if (n == 1) {System.out.println("第" + n + "个棋子从" + a + "到" + b);System.out.println("第" + n + "个棋子从" + b + "到" + c);v=v+2;} else {l(a, b, c, n - 1);System.out.println("第" + n + "个棋子从" + a + "到" + b);v=v+1;l(c, b, a, n - 1);System.out.println("第" + n + "个棋子从" + b + "到" + c);v=v+1;l(a,b,c,n-1);} }
最后一种就是循环汉诺塔了
(这个图是我剽窃的,大家可以去知乎上看原文)
(因为我觉得他讲到很麻烦,所以给大家看一下比较简单的(个人想法))
(但是他写的很细,大佬可以去看一下);
所谓“循环移动” 就是在原始的汉诺塔问上增加一个要求:
设A柱、B柱、C柱(及A柱)构成一个顺时针方向的三角形,
(这个暂时还没想到,想到了再补充,大家可以留言帮我解一下这个问题)
我们刚刚都看到汉诺塔已经采用了高级点的东西(分治算法)
那分治算法又是啥呢?
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,
而本次的汉诺塔就采用了分治算法
无论有多少层圆盘我都当作2个去看
我们拿n=3细讲一下,就会发现只要我们把最下面那个盘子移动到第三根柱子后,剩下的就是移动两个盘子,又回到了两个盘子的状态,当n=4时,也是如此。。。。。直到n=5;
所以无论有多少个盘子,都可以当成两个盘子对待。
至于为什么 if (n == 1) {}里是输出一个还是输出两个是跟他的盘子只有一个的时候有关系的
当n=1是在无变体时,一个盘子直接移动到第三个盘子,所以时a=》c
在邻近时要经过b就是先a=》b,再b=》c;
至于下面else里的内容怎么看出来的呢?
在无变体时
a=>b,a=>c,b=>c
根据递归的思想,当他到达最后一层后就立刻返回,开始运行。
所以最后一层就是第一个答案(有点绕)
所以当n=1时a=》c;
当n=2时
注意顺序是a先到b,而不是先到c,所以应该
(a,c,b,n-1);
可能看这个还是比较绕的
先把这里的a=1,b=2,c=3;
这样1=》3就是a=》b
而下面的
System.out.println("第"+n+"个棋子从"+a+"到"+c);
因为第一个递归已经结束了,开始本来的
(a,b,c,n)开始运行了
就是第二个盘子直接移动到3;
最后一个
d(b,a,c,n-1);
就是1=》3就是b=》c;
邻近汉诺塔解释
大家可以比对着
同样的原理
if (n == 1) {System.out.println("第" + n + "个棋子从" + a + "到" + b);System.out.println("第" + n + "个棋子从" + b + "到" + c);}
也是当n=1时的移动路径
else {l(a, b, c, n - 1);System.out.println("第" + n + "个棋子从" + a + "到" + b);v=v+1;l(c, b, a, n - 1);System.out.println("第" + n + "个棋子从" + b + "到" + c);v=v+1;l(a,b,c,n-1);}
我刚刚说了先把无论多少个盘子都当两个看,你会发现当n>=2时都适用
当n=2时移动轨迹
第1个棋子从1到2
第1个棋子从2到3
第2个棋子从1到2
第1个棋子从3到2
第1个棋子从2到1
第2个棋子从2到3
第1个棋子从1到2
第1个棋子从2到3
(建议大家手动移动一下,印象更深刻一点)
l(a, b, c, n - 1);
我们发现前两个刚刚好可以a=》b,b=》c,所以直接这么去写
然后我们下面怎么办呢
这时第一个递归结束向下走
这时候又返回到(a,b,c,n)
所以可以直接
System.out.println("第"+n+"个棋子从"+a+"到"+c);
下面我们发现是从3=》2,2=》1,符合当n=1时的规矩
l(c, b, a, n - 1);
下面又是第二个棋子
System.out.println("第" + n + "个棋子从" + b + "到" + c);
再最后一步
l(a,b,c,n-1);
(大家可以把这当成一种记忆方法,原理太麻烦了)
以上就是我对汉诺塔的总结,欢迎小伙伴们随时指错和补充。
汉诺塔细讲(内含邻近,循环。以及作者对汉诺塔,以及分治算法的小感悟,注释)相关推荐
- 【Java数据结构与算法】第十七章 二分查找(非递归)和分治算法(汉诺塔)
第十七章 二分查找(非递归)和分治算法(汉诺塔) 文章目录 第十七章 二分查找(非递归)和分治算法(汉诺塔) 一.二分查找 1.思路 2.代码实现 二.分治算法(汉诺塔) 1.概述 2.汉诺塔 一.二 ...
- 三十三、分治算法---汉诺塔问题
一.分治算法的介绍 分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或 相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以 ...
- 分治算法---汉诺塔
思路分析 代码实现 package com.atguigu.dac;public class Hanoitower {public static void main(String[] args) {h ...
- 算法- 分治算法(实现汉诺塔)
package Algorithm.dac;public class Hannoitower {public static void main(String []args){hannoiTower(5 ...
- 二分查找、分治算法——汉诺塔问题
一.二分查找算法(非递归) 1)二分查找法只适用于从有序的数列中进行查找(比如数字和字母等),将数列排序后在进行查找 2)二分查找算法的运行时间为对数时间,即查找到需要的目标位置最多只需要log以2为 ...
- NYIST汉诺塔(一)(三)问题以及汉诺塔的路径实现
首先,什么是汉诺塔?如题,简单的介绍一下:在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地 ...
- 分治算法(汉诺塔游戏)
分治算法 分治算法就是将原问题分解成n个规模较小,并且结构与原问题相似的子问题,再去递归地解决这些子问题,然后这些子问题,然后再合并其结果,就可以得到原问题的解. 分治算法的递归实现,每一层递归都会涉 ...
- 分治算法求解汉诺塔问题
1.什么是分治算法? 分治算法,字面理解"分而治之",就是把一个复杂的问题分成两个或者更多的相同或者相似的子问题,再把子问题分成更小的子问题...直到最后子问题可以直接简单求解,原 ...
- 分治算法——汉诺塔(HanoiTower)
分治算法--汉诺塔 介绍 分治算法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题···直到最后子 ...
最新文章
- LINUX中断学习笔记【转】
- 页面重新跳转到父类url
- struts 模块化开发学习
- 12月碎碎念-随便聊聊这一年
- java criteria exist_Java Criteria.addExists方法代碼示例
- C#的未来:扩展属性及更多
- Spring4 MVC HelloWorld 注解和JavaConfig实例
- centos 6.6 mysql5.7_CentOS 6.5/6.6 安装(install)mysql 5.7 最完整版教程-Go语言中文社区...
- MSSQL中Case语句的用法
- 七种场景下的软件作业量估计
- 快递鸟批量打印电子面单接口及控件安装
- 详解FAT12文件系统
- 《python网络爬虫和信息提取》:全球电影票房排行榜(附更改后的代码)
- socket.io实现一对多的在线咨询客服系统
- Finecms基础操作手册
- 群晖nas介绍文档_我的NAS我的地盘 篇三:群晖NAS软件介绍与应用之DS file篇
- 算法竞赛宝典 递归算法 地盘划分
- NBA名人堂之-朱利叶斯·欧文|埃尔文·海耶斯|多尔夫·谢伊斯|鲍勃·佩蒂特|戴夫·冰
- 基于硬件的C(C++)语言程序设计教程5:更改Atmel Studio的语言设置
- 大一集训--c++ set集合
热门文章
- 分布式机器学习——模型并行训练
- java aes对称加密算法_Java实现AES对称加密算法
- android+qq+4.6.2,AndroidQQ通讯录4.6闪亮登场 让你领略“超快感”
- 开展计算机课程的目的,信息工程学院开展“计算机应用基础”课程教学研讨会...
- 颜色空间探究:RGB、HSV和HSL
- vuex module总结
- linux 内核 面试,LINUX内核经典面试题
- pwn的学习8 leg
- 2021影像上海艺术博览会即将回归,多维度呈现本土影像艺术活力
- CRM销售系统价格 一套CRM销售系统多少钱