动态规划——背包问题(运输货物问题)
先学习 01背包问题
背包问题可大致分为【完全背包问题】和【多重背包问题】
分析问题:
原问题:在满足重量约束的条件下,将这 m 件物品选择性的放入容量位W的背包中所能获得的最大利润。
子问题:在满足重量约束的条件下,将 前 i(i<=m)件物品选择性的放入容量为 j(j<=W)的背包中所能获得的最大利润。
定义状态: f(i,j)为前 i 件物品选择性放入 容量为 j (j<= W)中获得最大利润。那么 f(m,W)就是我们的原问题。
存在两个参数,所以创建一个二维DP数组。
vi表示第 i 件物品的价值,wi 表示第 i 件物品的重量
寻找状态转移方程
边界条件(初始条件)
构建方程:
- 当 i > 1 和 j > 1 的情况: 考虑以下:由一个容量大小为j的背包,已经规划好了 前面 i-1 件物品的装载方案,现在你只需要考虑装不装第 i 件物品。
所以接下来,考虑两种情况:
转移方程:
代码实现:
public static void valueMax(int[] weight, int[] value, int capacity) {
//这里 weight和value是一样从的。 表示 物品的个数
int num = value.length;
int[][] dp = new int[weight.length+1][capacity+1];
//记录放入商品的情况
int[][] path = new int[weight.length+1][capacity+1];
// 第一行 将可以放下的 第一物品 放入
for (int j = 0; j < dp.length; j++) {
dp[j][0] = 0;
}
// 第一列 背包容量为1的 ,可以装下哪些物品
for (int i = 0; i < dp[0].length; i++) {
dp[0][i] = 0;
}
// 然后从 第 一行和第一列 开始
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if (j >= weight[i-1]) { //这里因为是从第一行开始 使用对应的第一个是 weight[i-1]
// 还是 应为 我们 下标是从 1开始的,所以对应的公式需改动 即 物品的重量和价格需 下标要减1
//dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
// dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i-1]] + value[i-1]);
// 为了 存储 选择 放入背包的是哪些物品 所以使用 选择来实现
if(dp[i-1][j] < dp[i-1][j-weight[i-1]]+value[i-1]) {
dp[i][j] = dp[i-1][j-weight[i-1]]+value[i-1];
path[i][j] = 1;
}else {
dp[i][j] = dp[i-1][j];
}
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
System.out.println("动态规划表如下:");
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[i].length; j++) {
System.out.print(dp[i][j] + "\t");
}
System.out.println();
}
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-=weight[i-1];
}
i--;
}
}