1 01背包
/**
* 时间: O(VN)
* 空间: O(VN)
*/
public static int zeroOnePack1(int[] c, int[] w, int n, int v) {
int[][] dp = new int[n][v + 1];
for (int i = 1; i < n; i++) {
for (int j = v; j >= 0; j--) {
dp[i][j] = dp[i - 1][j];
if (j - c[i] >= 0) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - c[i]] + w[i]);
}
}
}
return dp[n - 1][v];
}
/**
* 时间: O(VN)
* 空间: O(V)
*/
public static int zeroOnePack2(int[] c, int[] w, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 1; i < n; i++) {
for (int j = v; j >= 0; j--) {
dp[j] = dp[j];
if (j - c[i] >= 0) {
dp[j] = Math.max(dp[j], dp[j - c[i]] + w[i]);
}
}
}
return dp[v];
}
public static void main(String[] args) {
int[] c = {0, 1, 2, 2, 3, 4};
int[] w = {0, 2, 3, 4, 4, 5};
int n = c.length;
int v = 5;
System.out.println(zeroOnePack1(c, w, n, v));
System.out.println(zeroOnePack2(c, w, n, v));
}
2 完全背包
/**
* 时间: O(V*∑(V/c[i]))
* 空间: O(VN)
*/
public static int completePack1(int[] c, int[] w, int n, int v) {
int[][] dp = new int[n][v + 1];
for (int i = 1; i < n; i++) {
for (int j = 0; j <= v; j++) {
for (int k = 0; j - k * c[i] >= 0; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * c[i]] + k * w[i]);
}
}
}
return dp[n - 1][v];
}
/**
* 时间: O(VN)
* 空间: O(V)
*/
public static int completePack2(int[] c, int[] w, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 1; i < n; i++) {
for (int j = 0; j <= v; j++) {
if (j - c[i] >= 0) {
dp[j] = Math.max(dp[j], dp[j - c[i]] + w[i]);
}
}
}
return dp[v];
}
public static void main(String[] args) {
int[] c = {0, 1, 2, 3, 4};
int[] w = {0, 2, 4, 4, 5};
int n = c.length;
int v = 5;
System.out.println(completePack1(c, w, n, v));
System.out.println(completePack2(c, w, n, v));
}
3 多重背包
/**
* 时间: O(V*N*∑(V/s[i]))
* 空间: O(VN)
*/
public static int multiplePack1(int[] c, int[] w, int[] s, int n, int v) {
int[][] dp = new int[n][v + 1];
for (int i = 1; i < n; i++) {
for (int j = v; j >= 0; j--) {
for (int k = 0; k <= s[i] && j - k * c[i] >= 0; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * c[i]] + k * w[i]);
}
}
}
return dp[n - 1][v];
}
/**
* 一维化
* 时间: O(V*N*∑(V/s[i]))
* 空间: O(V)
*/
public static int multiplePack2(int[] c, int[] w, int[] s, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 1; i < n; i++) {
for (int j = v; j >= 0; j--) {
for (int k = 0; k <= s[i] && j - k * c[i] >= 0; k++) {
dp[j] = Math.max(dp[j], dp[j - k * c[i]] + k * w[i]);
}
}
}
return dp[v];
}
/**
* 转换为01背包
* 时间: O(V*N*∑(V/s[i]))
* 空间: O(V)
*/
public static int multiplePack3(int[] c, int[] w, int[] s, int n, int v) {
int count = 0;
for (int i = 0; i < n; i++) {
count += s[i];
}
int[] cc = new int[count + 1];
int[] ww = new int[count + 1];
count = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < s[i]; j++) {
cc[count] = c[i] * (j + 1);
ww[count] = w[i] * (j + 1);
count++;
}
}
n = cc.length;
return zeroOnePack(cc, ww, n, v);
}
/**
* 二进制优化
*/
public static int multiplePack4(int[] c, int[] w, int[] s, int n, int v) {
List<Num> nums = new LinkedList<>();
nums.add(new Num(0, 0));
Num num = null;
for (int i = 0; i < n; i++) {
int j = 1;
while (j <= s[i]) {
num = new Num(j * c[i], j * w[i]);
nums.add(num);
j = j * 2;
}
// last
if (num != null){
j = s[i] - (j / 2 - 1);
num.c = j * c[i];
num.w = j * w[i];
}
}
int[] cc = new int[nums.size()];
int[] ww = new int[nums.size()];
int k = 0;
for (Num num1 : nums) {
cc[k] = num1.c;
ww[k] = num1.w;
k++;
}
return zeroOnePack(cc, ww, cc.length,v );
}
public static class Num {
public int c;
public int w;
public Num(int c, int w) {
this.c = c;
this.w = w;
}
}
public static int zeroOnePack(int[] c, int[] w, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 0; i < n; i++) {
for (int j = v; j >= 0; j--) {
if (j - c[i] >= 0) {
dp[j] = Math.max(dp[j], dp[j - c[i]] + w[i]);
}
}
}
return dp[v];
}
public static void main(String[] args) {
int[] c = {0, 1, 2, 3, 4};
int[] w = {0, 2, 4, 4, 5};
int[] s = {0, 3, 1, 3, 10};
int n = c.length;
int v = 5;
System.out.println(multiplePack1(c, w, s, n, v));
System.out.println(multiplePack2(c, w, s, n, v));
System.out.println(multiplePack3(c, w, s, n, v));
System.out.println(multiplePack4(c, w, s, n, v));
}
4 混合背包
public static int mixPack1(int[] c, int[] w, int[] s, int n, int v) {
int[] dp = new int[v + 1];
for (int i = 1; i < n; i++) {
if (s[i] == -1) {
// 01背包问题
for (int j = v; j >= 0; j--) {
if (j - c[i] >= 0) {
dp[j] = Math.max(dp[j], dp[j - c[i]] + w[i]);
}
}
} else if (s[i] == 0) {
// 完全背包问题
for (int j = 0; j <= v; j++) {
if (j - c[i] >= 0) {
dp[j] = Math.max(dp[j], dp[j - c[i]] + w[i]);
}
}
} else if (s[i] > 0) {
// 多重背包问题
for (int j = v; j >= 0; j--) {
for (int k = 0; k <= s[i] && j - k * c[i] >= 0; k++) {
dp[j] = Math.max(dp[j], dp[j - k * c[i]] + k * w[i]);
}
}
}
}
return dp[v];
}
public static void main(String[] args) {
int[] c = {0, 1, 2, 3, 4};
int[] w = {0, 2, 4, 4, 5};
int[] s = {-1, -1, 1, 0, 2};
int n = c.length;
int v = 5;
System.out.println(mixPack1(c, w, s, n, v));
}
5 二维费用背包
public static int twoPack(int[] c1, int[] c2, int[] w, int n, int v,int m) {
int[][] dp = new int[v + 1][m + 1];
for (int i = 1; i < n; i++) {
for (int j = v; j >= 0; j--) {
for (int k = m; k >= 0; k--) {
if (j - c1[i] >= 0 && k - c2[i] >= 0){
dp[j][k] = Math.max(dp[j][k], dp[j - c1[i]][k - c2[i]] + w[i]);
}
}
}
}
return dp[v][m];
}
public static void main(String[] args) {
int[] c1 = {0, 1, 2, 3, 4};
int[] c2 = {0, 2, 4, 4, 5};
int[] w = {0, 3, 4, 5, 6};
int n = c1.length;
int v = 5;
int m = 6;
System.out.println(twoPack(c1, c2, w, n, v, m));
}
参考
背包九讲