01背包问题
完全背包问题
多重背包问题
分组背包问题
AcWing 2. 01背包问题 原题链接
有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000 0<vi,wi≤10000<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
朴素写法:
private static int function1() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
}
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = 0; j < m + 1; j++) {
if (j >= a[i - 1][0])
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - a[i - 1][0]] + a[i - 1][1]);
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[n][m];
}
空间优化写法:
private static int function2() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
}
int[] dp = new int[m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = m; j >= a[i - 1][0]; j--) {
dp[j] = Math.max(dp[j], dp[j - a[i - 1][0]] + a[i - 1][1]);
}
}
return dp[m];
}
AcWing 3. 完全背包问题 原题链接
有 NN 种物品和一个容量是 VV 的背包,每种物品都有无限件可用。
第 ii 种物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000 0<vi,wi≤10000<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
朴素写法:
private static int function1() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
}
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = 0; j < m + 1; j++) {
for (int k = 0; k * a[i - 1][0] <= j; k++)
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * a[i - 1][0]] + k * a[i - 1][1]);
}
}
return dp[n][m];
}
维度优化写法:
private static int function2() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
}
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = 0; j < m + 1; j++) {
if (j >= a[i - 1][0])
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - a[i - 1][0]] + a[i - 1][1]);
else dp[i][j] = dp[i - 1][j];
}
}
return dp[n][m];
}
维度+空间优化写法
private static int function3() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
}
int[] dp = new int[m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = a[i - 1][0]; j < m + 1; j++) {
dp[j] = Math.max(dp[j], dp[j - a[i - 1][0]] + a[i - 1][1]);
}
}
return dp[m];
}
AcWing 4. 多重背包问题 原题链接
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000<N,V≤100 0<vi,wi,si≤1000<vi,wi,si≤100
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
朴素写法:
private static int function1() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][3];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
a[i][2] = in.nextInt();
}
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = 0; j < m + 1; j++) {
for (int k = 0; k <= a[i - 1][2] && j >= k * a[i - 1][0]; k++)
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * a[i - 1][0]] + k * a[i - 1][1]);
}
}
return dp[n][m];
}
二进制优化写法:
private static int function2() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][3];
//b的长度是n*logn
int[][] b = new int[25000][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
a[i][2] = in.nextInt();
}
int idx = 0;
for (int i = 0; i < n; i++) {
int k = 1;
while (k <= a[i][2]) {
b[idx][0] = a[i][0] * k;
b[idx][1] = a[i][1] * k;
a[i][2] -= k;
k <<= 1;
idx++;
}
if (a[i][2] > 0) {
b[idx][0] = a[i][0] * a[i][2];
b[idx][1] = a[i][1] * a[i][2];
idx++;
}
}
int[] dp = new int[m + 1];
for (int i = 1; i < idx + 1; i++) {
for (int j = m; j >= b[i - 1][0]; j--) {
dp[j] = Math.max(dp[j], dp[j - b[i - 1][0]] + b[i - 1][1]);
}
}
return dp[m];
}
AcWing 5. 多重背包问题 II 原题链接
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N≤10000<N≤1000 0<V≤20000<V≤2000 0<vi,wi,si≤20000<vi,wi,si≤2000
提示:
本题考查多重背包的二进制优化方法。
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
private static int function() {
int n = in.nextInt();
int m = in.nextInt();
int[][] a = new int[n][3];
//b的长度是n*logn
int[][] b = new int[25000][2];
for (int i = 0; i < n; i++) {
a[i][0] = in.nextInt();
a[i][1] = in.nextInt();
a[i][2] = in.nextInt();
}
int idx = 0;
for (int i = 0; i < n; i++) {
int k = 1;
while (k <= a[i][2]) {
b[idx][0] = a[i][0] * k;
b[idx][1] = a[i][1] * k;
a[i][2] -= k;
k <<= 1;
idx++;
}
if (a[i][2] > 0) {
b[idx][0] = a[i][0] * a[i][2];
b[idx][1] = a[i][1] * a[i][2];
idx++;
}
}
int[] dp = new int[m + 1];
for (int i = 1; i < idx + 1; i++) {
for (int j = m; j >= b[i - 1][0]; j--) {
dp[j] = Math.max(dp[j], dp[j - b[i - 1][0]] + b[i - 1][1]);
}
}
return dp[m];
}
AcWing 9. 分组背包问题 原题链接
有 NN 组物品和一个容量是 VV 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,VN,V,用空格隔开,分别表示物品组数和背包容量。
接下来有 NN 组数据:
- 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
- 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000<N,V≤100 0<Si≤1000<Si≤100 0<vij,wij≤1000<vij,wij≤100
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
朴素写法:
private static class Packet {
int weight;
int value;
public Packet(int weight, int value) {
this.weight = weight;
this.value = value;
}
}
private static int function1() {
int n = in.nextInt();
int m = in.nextInt();
Packet[][] a = new Packet[n][];
int[] size = new int[n];
for (int i = 0; i < n; i++) {
int s = in.nextInt();
size[i] = s;
a[i] = new Packet[s];
for (int j = 0; j < s; j++) {
a[i][j] = new Packet(in.nextInt(), in.nextInt());
}
}
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = 0; j < m + 1; j++) {
// 这一组可以一种也不选
dp[i][j] = dp[i - 1][j];
for (int k = 0; k < size[i - 1]; k++) {
if (j >= a[i - 1][k].weight)
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - a[i - 1][k].weight] + a[i - 1][k].value);
}
}
}
return dp[n][m];
}
空间优化写法:
private static class Packet {
int weight;
int value;
public Packet(int weight, int value) {
this.weight = weight;
this.value = value;
}
}
private static int function2() {
int n = in.nextInt();
int m = in.nextInt();
Packet[][] a = new Packet[n][];
int[] size = new int[n];
for (int i = 0; i < n; i++) {
int s = in.nextInt();
size[i] = s;
a[i] = new Packet[s];
for (int j = 0; j < s; j++) {
a[i][j] = new Packet(in.nextInt(), in.nextInt());
}
}
int[] dp = new int[m + 1];
for (int i = 1; i < n + 1; i++) {
for (int j = m; j >= 0; j--) {
for (int k = 0; k < size[i - 1]; k++) {
if (j >= a[i - 1][k].weight)
dp[j] = Math.max(dp[j], dp[j - a[i - 1][k].weight] + a[i - 1][k].value);
}
}
}
return dp[m];
}