常用算法——分治算法(汉诺塔)

分治算法介绍

  1. 分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)……
  2. 分治算法可以求解的一些经典问题
     二分搜索
     大整数乘法
     棋盘覆盖
     合并排序
     快速排序
     线性时间选择
     最接近点对问题
     循环赛日程表
    汉诺塔

分治算法的基本步骤

分治法在每一层递归上都有三个步骤:
1) 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题
2) 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
3) 合并:将各个子问题的解合并为原问题的解。

分治(Divide-and-Conquer§)算法设计模式如下:

if |P|≤n0
then return(ADHOC§)
//将P分解为较小的子问题 P1 ,P2 ,…,Pk
for i←1 to k
do yi ← Divide-and-Conquer(Pi) 递归解决Pi
T ← MERGE(y1,y2,…,yk) 合并子问题
return(T)

说明:
其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC§是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时直接用算法ADHOC§求解。算法MERGE(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,…,Pk的相应的解y1,y2,…,yk合并为P的解。

分治算法最佳实践-汉诺塔

汉诺塔的传说

汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘在三根柱子之间一次只能移动一个圆盘

假如每秒钟一次,共需多长时间呢?移完这些金片需要5845.54 亿年以上,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54 亿年,地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。

汉诺塔游戏的演示和思路分析:

  1. 如果是有一个盘, A->C
  2. 如果我们有n >= 2 情况,我们总是可以看做是两个盘1.最下边的盘2. 最上面的(所有盘)看成一个盘
    (1)先把最上面的所有盘A->B
    (2) 把最下边的盘A->C
    (3)把B 塔的所有盘从B->C

汉诺塔游戏的代码实现:

第一个盘是从上往下数的

public class Hanoitower {

	public static void main(String[] args) {
		hanoiTower(10, 'A', 'B', 'C');
	}

	// 汉诺塔的移动的方法
	// 使用分治算法

	public static void hanoiTower(int num, char a, char b, char c) {
		// 如果只有一个盘
		if (num == 1) {
			System.out.println("第1个盘从 " + a + "->" + c);
		} else {
			// 如果我们有 n >= 2 情况,我们总是可以看做是两个盘 1.最下边的一个盘 2. 上面的所有盘
			// 1. 先把 最上面的所有盘 A->B, 移动过程会使用到 c
			hanoiTower(num - 1, a, c, b);
			// 2. 把最下边的盘 A->C
			System.out.println("第" + num + "个盘从 " + a + "->" + c);
			// 3. 把B塔的所有盘 从 B->C , 移动过程使用到 a塔
			hanoiTower(num - 1, b, a, c);

		}
	}

}

理解

   代码很简洁,可能对于递归不是很理解的同学觉得有些吃力,下面我来具体解释下递归的流程。
当n=64时,前63个要想办法成功移动到b柱上,64号是Boss,他不管上面的63个小弟用什么办法,我可以先等着,前面63个小弟可以利用我的c柱,于是64号在等着上面63号完成移到b柱,现在63是临时老大,他也想去c柱,于是他命令前62号移到b柱,他等着,62号也采取之前两个的做法,于是这个命令一直往前传,没办法,上面被压着自己也没法动啊。
终于到了1号,他是现在唯一能动的,于是1号移动到了b柱,好了,2号可以到c柱,2第一个到目的地,心里十分激动,我都到c柱,舒服。不过当他看到a柱上的3号时,猛然一惊,我还有个上司,好吧得完成任务啊,于是让1号移到c柱,3号可以到b柱了,之后1号和2号在想办法到b柱,于是1,2,3号在b柱,4号一看很满意,但我得到b柱啊,嗯,1,2,3号你们按照刚才的办法到c柱,空出b柱给我。唉,接着折腾,后面的5号一直到63号都是这么折腾的,终于前63号移动到b柱,64号直接跑到了c柱,他觉得这些小弟办事效率真不行,不过他还是招呼小弟到c柱。
于是剩下在b柱的63个小弟还要再干一遍他们在a柱上干的事,这里来看,1号操作的频率是最高的,而64号只要移动一次就行了,要是在现实中让人这么去干,估计早就被逼疯了。
如果真要解释代码的每一步执行过程,那会很乱,两层递归,最后自己也会被绕的晕头转向,这个时候只要理解递归最终的解决的问题是什么就行了,中间的事交给程序,递归可以很绕也可以很直接,我们按照最直接的理解就行了。
最后关于递归算法,这中解决问题的方法也只有计算机才喜欢,我们虽然看着代码很简单,但真要深入理解也是很费脑细胞的,不过递归确实有中数学上的简洁美和逻辑美。

转至:https://www.baidu.com/link?url=9V4wa85bcO5t_xX0d5E-rQWQw3ENp11eOexJVNHj-opao66Rvl9xtk2E20vH7aRoPDEPDE8O4TKngS3tZrTYNXAY4GtnkazpTBTtJXhpOuW&wd=&eqid=908200660005c4b0000000065fa640c9

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值