题目描述
考题式描述
有N件物品和一个最多能背重量为W的背包(也就是说背包的容量是W),第i件物品的重量是weight[i],其价值是value[i],每件物品只能背一次,求解将哪些物品放到背包里面物品价值的总和最大。
简易版描述
贼,夜入豪宅,可偷之物甚多,而负重能力有限,偷哪些才更加不枉此行?
题目举例
| 物品编号 | 1 | 2 | 3 | 4 |
| 重量 | 2 | 1 | 3 | 2 |
| 价值 | 3 | 2 | 4 | 2 |
| 背包容量为5 |
解题思路
动态规划
根据举例中,直接找出答案比较困难,通过将其拆分成子问题,先从1个物品,背包容量为1时开始递推,最终找到答案。
确定动态规划公式:
编号前i个物品,背包容量为j时,所能取最大价值为 dp[i][j]
那么开始确定递推关系:
当前背包容量为j,当前物品的编号为i,我们要不要将物品i放入包内
- 当前物品编号i不放入背包中,dp[i][j] = dp[i-1][j]
- 解释:不放入就是之前的值
- 当前物品编号i放入背包中,dp[i][j] = dp[i-1][j-weight[i]]+value[i]
- 剩余空间能放的最大价值 加上 放入就是当前的价值
- 如编号为2时,编号2的重量为1,放入后空间还剩5-1=4的空间,自然要根据前面填表中编号为1容量为4的最大值是多少算进去,方可总的最大
综上:在以上两种情况中选择最优的
dp[i][j] = Math.max( dp[i-1][j] , dp[i-1][j-weight[i]]+value[i] )
对样例进行填表
| 物品编号\容量 | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 3 | 3 | 3 | 3 |
| 2 | 0 | 2 | 3 | 5 | 5 | 5 |
| 3 | 0 | 2 | 3 | 5 | 6 | 7 |
| 4 | 0 | 2 | 3 | 5 | 6 | 7 |
编程代码 以Java为例
import java.util.Arrays;
public class 背包问题 {
public static void main(String[] args) {
/**
* 价值:v = {3, 2, 4, 2}
* 重量:w = {2, 1, 3, 2}
* 背包容量:C = 5
*/
int[] w = {2,1,3,2};
int[] v = {3,2,4,2};
int C = 5;
int len = w.length;
int[][] bags = new int[5][C+1];
for (int i = 1; i <= len; i++) {
for (int j = 0; j <= C; j++) {
//重量大于背包容量则不放入
if (w[i - 1] > j) {
bags[i][j] = bags[i-1][j];
}else {
bags[i][j] = Math.max(bags[i-1][j],bags[i-1][j-w[i-1]]+v[i-1]);
}
}
}
nums(bags);
}
static void nums(int[][] nums){
for (int i = 0; i < nums.length; i++) {
System.out.println(Arrays.toString(nums[i]));
}
}
}