题目
有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{
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");
}
}
我是杰少