题意
- 给定N件物品和一个容量为V的背包
- 每件物品具有价值和体积两个属性,且每件物品选择次数小于等于1
- 计算出背包所能够存放的最大价值
题解(二维dp)
-
用 f [ i ] [ j ] f[i][j] f[i][j] 表示只看前 i i i 个物品,背包容积为 j j j 时,背包能存放的最大价值
-
那么 a n s = ans= ans= m a x max max { f [ N ] [ 0 f[N][0 f[N][0 ~ V ] V] V] }
-
用 v [ i ] v[i] v[i] 和 w [ i ] w[i] w[i] 分别表示第 i i i 个物品的 体积 和 价值
-
f [ i ] [ j ] f[i][j] f[i][j] 的状态转移:
- 当没有选到第 i i i 个物品进背包时:此时看前 i i i 个物品且背包容积为 j j j 时背包能存放的最大价值等价于看前 i − 1 i-1 i−1 个物品且背包容积为 j j j 时背包能存放的最大价值,即 f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i - 1][j] f[i][j]=f[i−1][j]
- 当选到了第 i i i 个物品进背包时:此时看前 i i i 个物品且背包容积为 j j j 时背包能存放的最大价值等价于看前 i − 1 i-1 i−1 个物品且背包容积为 j − v [ i ] j-v[i] j−v[i] (v[i]为背包中已经占用的体积) 时背包能存放的最大价值加上 w [ i ] w[i] w[i] (背包中已经存在的物品的价值) ,即 f [ i ] [ j ] = f [ i − 1 ] [ j − v [ i ] ] + w [ i ] f[i][j]=f[i-1][j - v[i]] + w[i] f[i][j]=f[i−1][j−v[i]]+w[i]
- f [ i ] [ j ] = f[i][j]= f[i][j]=上面两种状态取值最大的那一个
-
复杂度分析:
- 时间复杂度:遍历了一个二维数组 N ( m n ) N(mn) N(mn)
- 空间复杂度:一个二维数组 N ( m n ) N(mn) N(mn)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 物品数量
int N = scanner.nextInt();
// 背包容积
int V = scanner.nextInt();
// 记录每个物品的体积和价值
int[] v = new int[N + 1], w = new int[N + 1];
// 输入数据
for (int i = 1; i <= N; i++) {
v[i] = scanner.nextInt();
w[i] = scanner.nextInt();
}
// 下面是二维dp
// f[i][j] 表示只看前 i 个物品,背包容积为 j 时,背包能存放的最大价值
int[][] f = new int[N + 1][V + 1];
// f[i][j] 数据初始化
f[0][0] = 0;// 这一步可以省略
// f[i][j] 状态转移
for (int i = 1; i <= N; i++) {
for (int j = 0; j <= V; j++) {
// 当没有选到第 i 个物品进背包时
f[i][j] = f[i - 1][j];
// 当选到了第 i 个物品进背包时
if (j >= v[i]) f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
int ans = 0;
// ans = max { f[N][0 ~ V] }
for (int j = 0; j <= V; j++)
ans = Math.max(ans, f[N][j]);
System.out.println(ans);
}
}
优化
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 物品数量
int N = scanner.nextInt();
// 背包容积
int V = scanner.nextInt();
// 记录每个物品的体积和价值
int[] v = new int[N + 1], w = new int[N + 1];
// 输入数据
for (int i = 1; i <= N; i++) {
v[i] = scanner.nextInt();
w[i] = scanner.nextInt();
}
int[] f = new int[V + 1];
for (int i = 1; i <= N; i++) {
for (int j = V; j >= v[i]; j--) {
f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
}
}
System.out.println(f[V]);
}
}