概述
一、动态规划算法
1.1 基本介绍
- 动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
- 动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
- 与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。 ( 即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解 )
- 动态规划可以通过填表的方式来逐步推进,得到最优解.
1.2 动态规划与分治法的区别:
- 相同点:基本思想均是将原问题分解成若干个子问题,先求子问题,然后从子问题的解得到原问题的解;
- 不同点:
- 适用于动态规划求解的问题,分解得到的子问题往往不是互相独立的;
- 动态规划为自底向上,而分治法为自顶向下。
二、背包问题
2.1 基本介绍
问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。
其中又分01背包(每个物品最多放一个)和完全背包(每种物品都有无限件可用)
首先这是物品的参数:
每个动态规划算法都从一个网格开始,背包问题的网格如下。
第一步: 假设能背包能装的物品只有一个吉他,那么不管背包的容量为多少,其背包所能装的价值都是1500。
第二步: 假设背包能装的物品为4磅的音响和1磅的吉他,当背包的容量为 1、2、3 时,背包中只能放入一个吉他,因为音响的重量为 4,因此无法放入到背包中。
当背包的容量为 4 时,刚好等于音响的重量。这个时候有两个选择:一是只放入一个吉他;二是只放入一个音响。由于音响的价值为 3000,大于吉他的价值,因此选择将音响放入背包,此时背包中的价值为 3000。
第三步: 假设背包能装的物品为4磅的音响、1磅的吉他和3磅的电脑,当背包容量为1、2时,背包中只能放一个吉他。
当背包的容量为 3 时,有两种选择:一是只放入一个吉他;二是只放入一个电脑。由于电脑的价值高于吉他,因此将电脑放入。此时背包的价值为 2000。
当背包的容量为 4 时,仍然有两种选择:一是放入一个吉他和电脑;二是只放入一个音响。由于吉他和电脑的总价值高于音响的价值,因此将吉他和电脑放入。此时背包的价值为 1500 + 2000 = 3500。
2.2 思路分析
每次遍历到的第i个物品,设v [ i ] 为第 i 个物品的价值 、w [ i ] 为第 i 个物品的重量,根据 w [ i ] 和 v [ i ] 来确定是否需要将该物品放入背包中。并假设有n个物品,背包的容量为C。再令v [ i ] [ j ] 表示在前i个物品中能够装入容量为 j 的背包中的最大价值。
分析步骤:
- 将背包表初始化,v[i][0]=v[0][j]=0 表示前0个物品装入容量为0的背包的最大价值设为0
- 当w[i]> j 时,即当新增的商品的重量大于当前背包的容量时,v[i][j] = v[i-1][j],就使用上一个单元格的装入策略
- 当j > = w [ i ] 时,即当新增的商品的重量小于等于当前背包的容量时,v[i][j] = max{ v[i-1][j], v[i] + v[i-1][ j-w[i] ] } 则最大价值为当前物品价值加背包剩余容量的最大价值
其中:
v[i-1][j]: 就是上一个单元格的装入的最大价值
v[i] : 表示当前商品的价值
v[i-1][j-w[i]] :在装了第i个物品之后,背包中剩余容量的最大价值
2.3 代码实现
package algorithm;
public class Knapsack {
public static void main(String[] args) {
int[] w = {0, 1, 4, 3}; // 物品的重量
int[] v = {0, 1500, 3000, 2000}; // 物品的价值
int num = w.length; // 物品的数量可能的个数 (0~3,共 3 个)
int weight = 5; // 背包的容量可能的个数 (0~4,共 5 个)
int[][] val = new int[num][weight]; // val[i][j] 表示前i个物品可选,背包容量为j时的最大价值
int[][] path = new int[num][weight]; // path[i][j] 用于标记第i个物品有没有放入容量为j的背包
for (int i = 1; i < num; i++) { // 遍历物品
for (int j = 1; j < weight; j++) { // 遍历背包容量
if (w[i] > j) { // 如果当前物品重量大于背包容量
val[i][j] = val[i - 1][j]; // 不装入
} else { // 如果当前物品重量小于等于背包容量
int value_1 = val[i - 1][j]; // 不放入第 i 个物品的背包价值
int value_2 = v[i] + val[i - 1][j - w[i]]; // 放入第 i 个物品后的价值
/* 把最大价值放入背包 */
if (value_1 > value_2) {
val[i][j] = value_1;
} else {
val[i][j] = value_2;
path[i][j] = 1; // 用于标记在本网格放入了第 i 个物品
}
}
}
}
// 最后一个网格就是最大价值
System.out.println("背包价值为:" + val[num - 1][weight - 1]);
// 由于最后一个网格就是最大价值
// 因此,逆序遍历 record 找到最后一个放入的物品,然后找到剩余空间价值是放入第几个物品
int i = path.length - 1;
int j = path[0].length - 1;
while (i > 0 && j > 0) {
if (path[i][j] == 1) {
System.out.printf("放入了第 %d 个商品n", i);
j = j - w[i]; // 背包剩余容量
}
i--;
}
}
}
最后
以上就是眯眯眼芒果为你收集整理的动态规划算法解决背包问题一、动态规划算法二、背包问题的全部内容,希望文章能够帮你解决动态规划算法解决背包问题一、动态规划算法二、背包问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复