本文已参与「新人创作礼」活动,一起开启掘金创作之路。
往期
题目
有 组物品和一个容量是 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 ,价值是 ,其中 是组号, 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 ,用空格隔开,分别表示物品组数和背包容量。
接下来有 组数据:
- 每组数据第一行有一个整数 ,表示第 个物品组的物品数量;
- 每组数据接下来有 行,每行有两个整数 ,用空格隔开,分别表示第 个物品组的第 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
解题思路
01背包问题中每种物品有两种策略:选或者不选,本题变成了每组物品有两种策略:选择本组的一件或者一件都不选。
- 状态定义
: 前组物品花费费用能取得的最大价值
- 状态转移方程
import java.util.*;
class Main {
private static final int S = 110;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 物品组数
int C = sc.nextInt(); // 背包容量
int[][] v = new int[N+1][S]; // 物品体积
int[][] w = new int[N+1][S]; // 物品价值
int[] s = new int[N+1]; // 每组物品数量
for (int i = 1; i <= N; i++) {
s[i] = sc.nextInt();
for (int j = 0; j < s[i]; j++) {
v[i][j] = sc.nextInt();
w[i][j] = sc.nextInt();
}
}
int[][] dp = new int[N+1][C+1];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= C; j++) {
dp[i][j] = dp[i-1][j]; // 不选第i组物品
for (int k = 0; k < s[i]; k++) { // 第i组物品中选一件
if (j >= v[i][k]) {
dp[i][j] = Math.max(dp[i][j], dp[i-1][j-v[i][k]] + w[i][k]);
}
}
}
}
System.out.println(dp[N][C]);
}
}
空间优化
类似01背包问题中空间优化,可将本题的二维dp数组优化为一维数组,仿照01背包的套路逆向枚举体积
import java.io.*;
import java.util.*;
public class Main {
private static final int S = 110;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 物品组数
int C = sc.nextInt(); // 背包容积
int[][] v = new int[N+1][S]; // 体积
int[][] w = new int[N+1][S]; // 价值
int[] s = new int[N+1];
for (int i = 1; i <= N; i++) {
s[i] = sc.nextInt();
for (int j = 0; j < s[i]; j++) {
v[i][j] = sc.nextInt();
w[i][j] = sc.nextInt();
}
}
int[] dp = new int[C+1];
for (int i = 1; i <= N; i++) {
for (int j = C; j >= 0; j--) {
for (int k = 0; k < s[i]; k++) {
if(j>=v[i][k]) {
dp[j] = Math.max(dp[j], dp[j - v[i][k]] + w[i][k]);
}
}
}
}
System.out.println(dp[C]);
}
}