https://blog.csdn.net/key_768/article/details/108202418?spm=1001.2014.3001.5502
分治算法
分治算法(Divide - and - Conquer)的思想在于“分”和“治” - 分而治之
-
“分”是将大问题分成独立的子问题,最后子问题可以简单的直接求解
-
“治”是将子问题解决,然后合成大问题,大问题的解是子问题解的合并
分治算法是很多问题的基本思想:如归并排序、快速排序、二分查找等
归并排序:
汉诺塔游戏
汉诺塔游戏
有3个塔,要求将塔A的圆盘放到塔C,条件:一次只能移动一个盘且大盘不能在小盘上,求移动的步骤及次数
当1个盘: 就是直接将盘从A移动到C即可
步骤 | 圆盘 | 移动 |
---|---|---|
第一步 | 盘1 | A -> C |
当2个盘: 需要3步,先将上面的小盘1放到B,再将大盘2放到C,最后将小盘1从B放到C
步骤 | 圆盘 | 移动 |
---|---|---|
第一步 | 盘1 | A -> B |
第二步 | 盘2 | A -> C |
第三步 | 盘1 | B -> C |
当3个盘: 需要7步(上面游戏可以尝试)
步骤 | 圆盘 | 移动 |
---|---|---|
第一步 | 盘1 | A -> C |
第二步 | 盘2 | A -> B |
第三步 | 盘1 | C -> B |
第四步 | 盘3 | A -> C |
第五步 | 盘1 | B -> A |
第六步 | 盘2 | B -> C |
第七步 | 盘1 | A -> C |
4个盘为15次,5个盘为31次
我们可以找到一些规律:
-
盘数为n,移动次数为2^n-1
-
中间步骤为:最下面的盘从A->C
算法分析:
我们可以把问题分解成三个步骤:
-
将盘分为最下面的盘n及其上的(n-1)盘,将n-1个盘移动到B
-
将盘n移动到C
-
将n-1个盘移动到C
问题是如何解决n-1个盘的移动?
继续分析盘的移动: 3个盘的7步分为1-3步、第4步和5-7步
-
1-3步:2个盘的3步其实与3个盘的1-3步类似,将1-3步中B/C互换,会发现与2个盘的3步一样
所以在最下的盘n移动前,n-1个盘移动规律:将n-1个盘从A移动到B
-
第4步,将最后一个盘移动到C
-
5-7步,其实也和2个盘相似,将5-7步A/B交换,就是2个盘的步骤
所以在最下的盘n移动后,n-1个盘移动规律:将n-1个盘从B移动到C
从上面可以看出,如何解决n-1个盘移动问题?
递归实现,n-1个盘的移动分为3步:
-
n-2个盘移动(B/C互换)
-
第n-1个盘从A移动到C
-
n-2个盘移动(A/B互换)
n-2就递归到n-3,直到为2个盘的移动
Java代码实现
具体思想都在上面,以下是具体实现
package com.company.十种算法.dac; /** * Author : zfk * Data : 17:50 * 分治算法解决汉诺塔问题 */ public class HanoiTower { public static void main(String[] args) { hanoi(3,'A','B','C'); } /** * * @param num 圆盘数 * @param A 塔A * @param B 塔B * @param C 塔C */ public static void hanoi(int num,char A,char B,char C){ //如果只有1个圆盘,当然只需移动一次:A -> C if (num == 1){ System.out.println("第1个盘:"+A+" -> "+C); } else { //1. n-1个盘移动: A -> B hanoi(num-1,A,C,B); //2. 第n个盘移动:A -> C System.out.println("第"+num+"个盘:"+A+" -> "+C); //3. n-1个盘移动:B -> C hanoi(num-1,B,A,C); } } } 12345678910111213141516171819202122232425262728293031323334353637383940414243