此文章不提供具体解题思路,仅提供模板。
你有一个容量为W的背包,n个物品,物品的重量为weight[i],价值为value[i],物品只有一件。求背包能装的最大价值。
dp[n + 1][W + 1]的二维数组初始化为0,dp[i][j]:i表示前i件物品,j表示当前的背包容量,则dp[i][j]表示i,j状态下背包的价值,只是当前最优,不过随着更新,dp[i][j]会变成全局最优。
public int solve(int[] weight, int[] value, int W, int n) {
int[][] dp = new int[n + 1][W + 1]; //已经全部初始化为0
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= W; ++j) {
if (j > weight[i]) {
dp[i + 1][j] = Math.max(dp[i][j], dp[i][j - weight[i]] + value[i]);
} else {
dp[i +1][j] = dp[i][j];
}
}
}
return dp[n][W];
}
空间优化: O(n^2) -> O(n)
public int solve(int[] weight, int[] value, int W, int n) {
int[] dp = new int[W + 1]; //初始化为0
for (int i = 0; i < n; ++i) {
for (int j = W; j >= weight[i]; --j) {//从后往前更新,因为后面的需要用到前面的数据
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
return dp[W];
}
你有一个容量为w的背包,n个物品,物品的重量为W[i],价值为V[i],物品数量无限。求背包能装的最大价值。
// 完全背包
public static int solve(int[] W, int[] V, int w) {
//已经初始化全部为0
// 第一维表示前几个物体 dp[0][x]表示前0个物品,即没有
// 第二维表示重量
int[][] dp = new int[W.length + 1][w + 1];
for (int i = 0; i < W.length; ++i) {//物品循环
for (int j = 0; j <= w; ++j) {//重量循环
for (int k = 0; k * W[i] <= j; ++k) {//数量循环
// k = 0的目的主要是第一次让dp[i + 1][j] = dp[i][j]
// 其后是为了比较,所以第一个dp的i要加1
dp[i + 1][j] = Math.max(dp[i + 1][j], dp[i][j - k * W[i]] + k * V[i]);
}
}
}
return dp[W.length][w];
}
优化:时间复杂度O(n^3) -> O(n^2) 空间复杂度O(n^2) -> O(n)
// 完全背包 时间、空间优化
public static int solve(int[] W, int[] V, int w) {
int[] dp = new int[w + 1];
for (int i = 0; i < W.length; ++i) {
for(int j = W[i]; j <= w; ++j) {
if (j >= W[i]) {
dp[j] = Math.max(dp[j], dp[j - W[i]] + V[i]);
}
}
}
return dp[w];
}
你有一个容量为w的背包,n个物品,物品的重量为W[i],价值为V[i],物品数量为C[i]。求背包能装的最大价值。
//第一、三层循环为01背包,第二层循环思想类似完全背包的优化
public static int getAnswer(int[] W, int[] V, int[] C, int n) {
int[] dp = new int[n + 1];
for (int i = 0; i < W.length; ++i) {
for (int k = 1; k <= C[i]; ++k) {
for (int j = n; j >= W[i]; --j) {
dp[j] = Math.max(dp[j], dp[j - W[i]] + V[i]);
}
}
}
return dp[n];
}
二进制优化
public static int getAnswer1(int[] W, int[] V, int[] C, int n) {
int[] dp = new int[n + 1];
for (int i = 0; i < W.length; ++i) {
for (int k = 1; C[i] > 0; k <<= 1) {
if (k > C[i]) k = C[i];
C[i] -= k;
for (int j = n; j >= W[i] *k; --j) {
dp[j] = Math.max(dp[j], dp[j - k * W[i]] + k * V[i]);
}
}
}
return dp[n];
}