题目
有 n 件物品和一个最多能背重量为 w 的背包。第 i 件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
解题思路
本题可以采用动态规划的方式来求解,首先第一步就是线确定 dp 数组。
我们用 dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为 j 的背包,价值总和最大是多少。那么可以有俩种方式来推导出 dp[i][j],即不在背包中放物品 i 和在背包中放物品 i。
不放物品 i: 由 dp[i - 1][j]推出,即背包容量为 j,里面不放物品 i 时的最大价值,其实就是当物品 i 的重量大于背包 j 的重量时,物品 i 无法放进背包中,此时 dp[i][j]就是 dp[i - 1][j],所以被背包内的价值依然和前面相同。
放物品 i: 由 dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为 j - weight[i]的时候不放物品 i 的最大价值,那么 dp[i - 1][j - weight[i]] + value[i] ,就是背包放物品 i 得到的最大价值。
接下来初始化 dp 数组:
当 j < weight[0]的时候,dp[0][j] 应该是 0,因为背包容量比编号 0 的物品重量还小;当 j >= weight[0]时,dp[0][j] 应该是 value[0],因为背包容量放足够放编号 0 物品。所以初始化的代码为:
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
复制代码
然后确定便利顺序,本题先遍历物品还是先遍历背包都是可以的,代码如下:
// weight数组的大小 就是物品个数
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
for(int i = 1; i < weight.size(); i++) { // 遍历物品
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
复制代码
代码实现
public static void testweightbagproblem(int[] weight, int[] value, int bagsize){
int wlen = weight.length, value0 = 0;
//定义dp数组:dp[i][j]表示背包容量为j时,前i个物品能获得的最大价值
int[][] dp = new int[wlen + 1][bagsize + 1];
//初始化:背包容量为0时,能获得的价值都为0
for (int i = 0; i <= wlen; i++){
dp[i][0] = value0;
}
//遍历顺序:先遍历物品,再遍历背包容量
for (int i = 1; i <= wlen; i++){
for (int j = 1; j <= bagsize; j++){
if (j < weight[i - 1]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
//打印dp数组
for (int i = 0; i <= wlen; i++){
for (int j = 0; j <= bagsize; j++){
System.out.print(dp[i][j] + " ");
}
System.out.print("\n");
}
}
复制代码
评论