给定两个长度都为N的数组weights和values,weights[i]和values[i]分别代表 i号物品的重量和价值
给定一个正数bag,表示一个载重bag的袋子,装的物品不能超过这个重量
返回能装下的最大价值
思路
代码实现
public class Code01_Knapsack {
// 所有的货,重量和价值,都在w和v数组里
// 为了方便,其中没有负数
// bag背包容量,不能超过这个载重
// 返回:不超重的情况下,能够得到的最大价值
public static int maxValue(int[] w, int[] v, int bag) {
if (w == null || v == null || w.length == 0 || v.length == 0) {
return 0;
}
return process(w, v, 0, bag);
}
/*普通暴力递归*/
// index 现在到达哪个位置
// bag 背包容量
public static int process(int[] w, int[] v, int index, int bag) {
if (bag < 0) { // 加入货物后超出背包容量,返回-1,表示这个货物不能加入
return -1;
}
if (index == w.length) { // 已经超出货物数量,递归结束,返回0
return 0;
}
// 背包容量不超,index合法
// 当前index货物 不放入背包
int p1 = process(w, v, index + 1, bag);
int p2 = 0;
// 判断当前货物能否加入背包
int nextFlag = process(w, v, index + 1, bag - w[index]);
if (nextFlag != -1) {
// 当前index货物 加入背包
p2 = v[index] + nextFlag;
}
return Math.max(p1, p2);
}
// 动态规划
public static int dp(int[] w, int[] v, int bag) {
if (w == null || v == null || w.length == 0 || v.length == 0) {
return 0;
}
int N = w.length;
int[][] dp = new int[N + 1][bag + 1];
// if (index == w.length) {return 0;}
// base case 最后一行(N行)的值全为0
// 每一行的数据都只依赖于他的下一行,所以从倒数第二行开始向上推
for (int index = N - 1; index >= 0; index--) {
for (int rest = 0; rest <= bag; rest++) {
int p1 = dp[index + 1][rest];
int p2 = 0;
int nextFlag = (rest - w[index]) < 0 ? -1 : dp[index + 1][rest - w[index]];
if (nextFlag != -1) {
p2 = v[index] + nextFlag;
}
dp[index][rest] = Math.max(p1, p2);
}
}
return dp[0][bag];
}
public static void main(String[] args) {
int[] weights = { 3, 2, 4, 7, 3, 1, 7 };
int[] values = { 5, 6, 3, 19, 12, 4, 2 };
int bag = 15;
System.out.println(maxValue(weights, values, bag));
System.out.println(dp(weights, values, bag));
}
}