题目
题目链接
解题思路
- 这是一个多重背包问题,每种物品有指定的数量限制
- 可以将多重背包转化为0-1背包来解决:
- 对每种物品,最多可以选择其数量上限个
- 使用逆序遍历避免重复计算
- 状态定义:
-
d
p
[
j
]
dp[j]
dp[j] 表示容量为
j
j
j 时能获得的最大价值
- 状态转移:
-
d
p
[
j
]
=
max
(
d
p
[
j
]
,
d
p
[
j
−
w
[
i
]
]
+
s
[
i
]
)
dp[j] = \max(dp[j], dp[j-w[i]] + s[i])
dp[j]=max(dp[j],dp[j−w[i]]+s[i])
代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, v;
cin >> n >> v;
vector<int> m(n);
vector<int> w(n);
vector<int> s(n);
vector<int> dp(v + 1, 0);
for(int i = 0; i < n; i++) {
cin >> m[i] >> w[i] >> s[i];
}
for(int i = 0; i < n; i++) {
for(int k = 0; k < m[i]; k++) {
for(int j = v; j >= w[i]; j--) {
dp[j] = max(dp[j], dp[j-w[i]] + s[i]);
}
}
}
cout << dp[v] << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int v = sc.nextInt();
int[] m = new int[n];
int[] w = new int[n];
int[] s = new int[n];
int[] dp = new int[v + 1];
for(int i = 0; i < n; i++) {
m[i] = sc.nextInt();
w[i] = sc.nextInt();
s[i] = sc.nextInt();
}
for(int i = 0; i < n; i++) {
for(int k = 0; k < m[i]; k++) {
for(int j = v; j >= w[i]; j--) {
dp[j] = Math.max(dp[j], dp[j-w[i]] + s[i]);
}
}
}
System.out.println(dp[v]);
}
}
def solve_knapsack(n, v, items):
dp = [0] * (v + 1)
for i in range(n):
m, w, s = items[i]
for k in range(m):
for j in range(v, w-1, -1):
dp[j] = max(dp[j], dp[j-w] + s)
return dp[v]
n, v = map(int, input().split())
items = []
for _ in range(n):
m, w, s = map(int, input().split())
items.append((m, w, s))
print(solve_knapsack(n, v, items))
算法及复杂度
- 算法:动态规划(多重背包转化为0-1背包)
- 时间复杂度:
O
(
n
⋅
v
⋅
∑
m
i
)
\mathcal{O}(n \cdot v \cdot \sum m_i)
O(n⋅v⋅∑mi) -
n
n
n 为物品种类,
v
v
v 为背包容量,
m
i
m_i
mi 为每种物品的数量
- 空间复杂度:
O
(
v
)
\mathcal{O}(v)
O(v) - 需要一个容量大小的
d
p
dp
dp 数组