文章目录
1. 分治算法 —— 汉诺塔问题
1. 分治算法的基本步骤
分治算法在每一层递归上都有三个步骤:
- 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
- 解决:若子问题规模较小而任意被解决,则直接解决,否则递归的解决各个子问题;
- 合并:将各个子问题的解合并为原问题的解
2. 经典案例 —— 汉诺塔
将 柱子 A 上的所有盘子移动到 柱子 C 上。
思路分析:
- 如果只有一个盘子,将这一个盘子从 A -> C上
- 如果有多个盘子,我们总是可以将这些盘子看作是两部分,第一部分:最下边的一个盘子,第二部分:剩余的所有盘子
- 先将最上边的盘子(第二部分)从 A -> B
- 再将最下边的盘子(第一部分)从 A -> C
- 最后将上边的盘子(B塔上的第二部分所有盘子)从 B -> C
汉诺塔问题代码:
package dac;
public class HanoiTower {
public static void main(String[] args) {
hanoiTower(5, 'A','B','C');
}
/**
* 将盘子从 a -> c
* @param num 盘的数量
* @param a 开始的柱子
* @param b 中间辅助的柱子
* @param c 目标柱子
*/
public static void hanoiTower(int num, char a, char b, char c){
if(num == 1){
System.out.println("第 1 个盘从 " + a + " -> " + c);
} else {
hanoiTower(num - 1, a, c, b);
System.out.println("第 " + num + " 个盘从 " + a + " -> " + c);
hanoiTower(num - 1, b, a, c);
}
}
}
2. 动态规划 —— 背包问题
1. 动态规划算法的介绍
- 动态规划算法的核心思想:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
- 与分治算法的区别:适合用动态规划求解的问题,经过分解往往不是相互独立的。即下一个子阶段的求解是建立在上一个子阶段的解的基础上进一步的求解。
- 动态规划问题可以通过填表的方法来逐步推进,得到最优解。
2. 经典案例 —— 背包问题
现有一个背包,容量为 4 磅,现有如下物品
1)求达到的目标为装入的背包的总价值最大,并且重量不超出背包的容量
2)要求装入的物品不能重复
3)通常的背包问题主要是指一个给定容量的背包、若干具有一定价值和重量的物品,选择物品放入背包使物品的价值最大。这里的背包问题属于01背包,即没有物品最多只能放一个,还有一种完全背包,即没有物品都有无限件可用,即可以重复
3. 思路分析
设置物品的重量数组为 w[i],物品的价格数组为 val[i],设v[i][j] 表示在前 i 个物品中能够装入容量为 j 的背包中的最大价值,即表中的 v[i][j] 数据表示背包为 j 重量下,有 i 件物品的情况下的最大价值。
填表分析:
- v[i][0] = v[0][j] = 0; //表示的就是 表格 中第一行和第一列都是 0
- 当 w[j] > j 时:v[i][j] = v[i - 1][j]; // 表示准备新增的商品的重量大于 当前背包的容量,就直接使用上一个单元格的装入策略;
- 当 w[j] <= j 时:v[i][j] = max{v[i - 1][j],val[i] + v[i - 1][j - w[i]]}; // 表示的是准备加入的新增的商品的容量小于等于当前背包的容量
- v[i - 1][j] —— 就是上一个单元格的装入策略
- val[i] + v[i - 1][j - w[i]] 中,val[i] —— 当前物品的重量,v[i - 1][j - w[i]] ,表示的是在当前物品满足背包的容量下,若背包还有剩余的空间,剩余空间的最大价值。
4. 代码实现:
package dynamic;
public class KnapsackProblem {
public static void main(String[] args) {
int[] w = {
1, 4, 3}; // 物品的重量
int[] val = {
1500, 3000, 2000}; // 物品的价值
int m = w.length; // 物品的个数
int n = 4; // 背包的容量
int[][] v = new int[m + 1][n + 1];
// 用来记录存放的商品的情况
int[][] path = new int[m + 1][n + 1];
for(int i = 0; i < v.length; i++){
// 第一列设置为 0
v[i][0] = 0;
}
for(int i = 0; i < v[0].length; i++){
// 第一行设置为 0
v[0][i] = 0;
}
for(int i = 1; i < v.length; i++){
for(int j = 1; j < v[i].length; j++){
if(j < w[i - 1]){
v[i][j] = v[i - 1][j];
} else {
// v[i][j] = Math.max(v[i - 1][j], val[i - 1] + v[i - 1][j - w[i - 1]]);
// 为了更好的记录应该放入的是哪些商品,应该采取下面的方法 —— 这两种方法都能计算价值
if(v[i - 1][j] > val[i - 1] + v[i - 1][