目录
一、背包内物品的总重量最大
题目:有n件物品,每件物品的重量为 weight = {2, 2, 4, 6, 3} 。现有一个容量为 w = 9 的背包,问背包内物品的总重量最大是多少。
1.1 0-1背包问题(二维数组求解)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
3 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
4 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 |
public static int knapsack(int[] weight, int n, int w) {
boolean[][] dp = new boolean[n][w+1]; // 默认值false
dp[0][0] = true; // 第一行的数据要特殊处理,可以利用哨兵优化
if (weight[0] <= w)
dp[0][weight[0]] = true;
for (int i = 1; i < n; ++i) { // 动态规划状态转移
for (int j = 0; j <= w; ++j) {
if (dp[i-1][j]==true) {
dp[i][j] = dp[i-1][j];
if(j <= w - weight[i])
dp[i][j + weight[i]] = true;
}
}
}
for (int i = w; i >= 0; --i) { // 输出结果
if (dp[n-1][i] == true) return i;
}
return 0;
}
1.2 0-1背包问题(一维数组求解)
和二维数组原理类似,只是每次会更新一维数组;
public static int knapsack2(int[] items, int n, int w) {
boolean[] dp = new boolean[w+1]; // 默认值false
dp[0] = true; // 第一行的数据要特殊处理,可以利用哨兵优化
if (items[0] <= w)
dp[items[0]] = true;
for (int i = 1; i < n; ++i) { // 动态规划
for (int j = w-items[i]; j >= 0; --j) //把第i个物品放入背包
if (dp[j]==true) dp[j+items[i]] = true;
}
for (int i = w; i >= 0; --i) // 输出结果
if (dp[i] == true) return i;
return 0;
}
1.3 完全背包问题(一维数组求解)
完全背包问题解题思路,每件物品可重复选择,weight = {2, 2, 4, 6, 3},w=9,dp[0 - w] 数组记录重量为 i 的最小次数。
状态变化如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 | 0 | 0 | 1 | 0 | 2 | 0 | 3 | 0 | 4 | 0 |
1 | 0 | 0 | 1 | 0 | 2 | 0 | 3 | 0 | 4 | 0 |
2 | 0 | 0 | 1 | 0 | 1 | 0 | 2 | 0 | 2 | 0 |
3 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 2 | 0 |
4 | 0 | 0 | 1 | 1 | 1 | 2 | 1 | 2 | 2 | 2 |
public static int knapsack3(int[] weight, int n, int w) {
int[] dp = new int[w+1];
int min = Integer.MAX_VALUE;
if (weight[0] <= w)
dp[weight[0]] = 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= w; ++j) {
if (j == 0 || dp[j] != 0 && j <= w - weight[i]) {
if(dp[j+weight[i]] != 0)
dp[j+weight[i]] = Math.min(dp[j+weight[i]], dp[j] + 1);
else
dp[j+weight[i]] = dp[j] + 1;
}
if(j == w && dp[w] != 0)
min = Math.min(min, dp[w]);
}
}
return min;
}
二、背包内物品的总价值最大
题目:有n件物品,每件物品的重量为 weight ={2, 2, 4, 6, 3}, value = {3, 4, 8, 9, 6}。现有一个容量为 w = 10 的背包,问如何选取物品放入背包,使得背包内物品的总重量最大。
2.1 0-1 背包问题(一维数组求解)
w | n | ||||||||||||
10 | 5 | ||||||||||||
weight | value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
2 | 3 | 0 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 4 | 1 | 0 | 0 | 4 | 4 | 7 | 7 | 7 | 7 | 7 | 7 | 7 |
4 | 8 | 2 | 0 | 0 | 4 | 4 | 8 | 8 | 12 | 12 | 15 | 15 | 15 |
6 | 9 | 3 | 0 | 0 | 4 | 4 | 8 | 8 | 12 | 12 | 15 | 15 | 17 |
3 | 6 | 4 | 0 | 0 | 4 | 4 | 8 | 10 | 12 | 14 | 15 | 18 | 18 |
public static int backpack(int[] weight, int[] value, int n, int w) {
int[] dp = new int[w+1];
for(int i=0; i<n; i++) {
for(int j=w; j>=0; j--) {
if(j >= weight[i])
dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i]);
}
}
return dp[w];
}
2.2 完全背包问题(一维数组求解)
w | n | ||||||||||||
10 | 5 | ||||||||||||
weight | value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
2 | 3 | 0 | 0 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 12 | 12 | 15 |
2 | 4 | 1 | 0 | 0 | 4 | 4 | 8 | 8 | 12 | 12 | 16 | 16 | 20 |
4 | 8 | 2 | 0 | 0 | 4 | 4 | 8 | 8 | 12 | 12 | 16 | 16 | 20 |
6 | 9 | 3 | 0 | 0 | 4 | 4 | 8 | 8 | 12 | 12 | 16 | 16 | 20 |
3 | 6 | 4 | 0 | 0 | 4 | 4 | 8 | 10 | 12 | 14 | 16 | 18 | 20 |
public static int backpack(int[] weight, int[] value, int n, int w) {
int[] dp = new int[w+1];
for(int i=0; i<n; i++) {
System.out.println(i + ":");
for(int j=0; j<=w; j++) {
if(j >= weight[i])
dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i]);
System.out.print(dp[j] + ", ");
}
System.out.println();
}
return dp[w];
}