有N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是v[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这是分组背包的第一类问题
至多只能选一件
所以状态转移方程为
所以对当前组的dp全部设为之前的状态值
for(int j = 0; j <= V; j++) {
dp[k][j] = dp[k - 1][j];
}
dp[i][j] = max(dp[i - 1][j - w[i]] + v[i], dp[i][j])
有N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是v[i]。这些物品被划分为若干组,每组中的物品互相冲突,至少选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这是分组背包的第二类问题
至少选一件
所以对当前组的dp全部设为负无穷
for(int j = 0; j <= V; j++) {
dp[k][j] = -INF;
}
这样可以保证当前一定会根据之前的背包来进行选择
也就是状态只能从之前的状态转移而来,不能保持原状态
即只能选而不能不选
所以状态转移方程为
dp[i][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]);
dp[i][j] = max(dp[i][j], dp[i - 1][j - w[i]] + v[i]);
第一个表示后续选的可以覆盖之前选的
第二个表示状态一定从之前的状态转移过来(至少一件物品)
有N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是v[i]。这些物品被划分为若干组,每组中的物品互相冲突,每个都可以选或者不选。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。分组背包的第三类问题
这个问题就是分组问题中的01背包问题,不再阐述。
习题:
HDU 3535
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 10;
int dp[maxn][maxn];
int main() {
int n, T;
// freopen("in.txt", "r", stdin);
while(cin >> n >> T) {
memset(dp, 0, sizeof(dp));
for(int k = 1; k <= n; k++) {
int m, s;
cin >> m >> s;
if(s == 0) {
for(int j = 0; j <= T; j++) {
dp[k][j] = -1e6;
}
}
if(s == 1 || s == 2) {
for(int j = 0; j <= T; j++) dp[k][j] = dp[k - 1][j];
}
for(int i = 1; i <= m; i++ ){
int t, w;
cin >> t >> w;
if(s == 0) {
for(int j = T; j >= t; j--) {
dp[k][j] = max(dp[k][j], dp[k][j - t] + w);
dp[k][j] = max(dp[k][j], dp[k - 1][j - t] + w);
}
}
if(s == 1) {
for(int j = T; j >= t; j--) {
dp[k][j] = max(dp[k][j], dp[k - 1][j - t] + w);
}
}
if(s == 2) {
for(int j = T; j >= t; j--) {
dp[k][j] = max(dp[k][j], dp[k][j - t] + w);
}
}
}
}
cout << max(dp[n][T], -1) << endl;
}
return 0;
}