分组背包
一、题目类型
题目描述
给定N组物品,其中第i组物品有$ num_i $个物品。第组的第j个物品的体积为 $ v_{ij} $,价值为。有一容积为的背包,要求选择若干个物品放入背包,使得每组至多选择一个物品并且物品总体积不超过V的前提下,物品的价值总和最大。
输入格式
第一行输入N, V,分别代表组N物品和背包容量V。
后面组物品数据,每组数据第一行一个$ num_i $,表示每组物品的数量,接着行,每行两个数 $num_i $ 和 $ p_{ij} $。
输出格式
1个数,每组至多选择一个物品并且物品总体积不超过V的前提下,物品的最大价值总和
二、分析
思路:
对于一组,有两种情况,选择本组某一件,与一件都不选;
划分:
背包容量为j时,背包获得的最大价值;
阶段:
dp[j]:背包容量为j时,背包获得的最大价值;
状态:
i:物品组号,1~n;
j:背包容量,v~0;
k:组内物品编号,1~sum[i];
状态转移方程:
$ dp[j] = \max{dp[j], dp[j - w[i][k]] + c[i][k]} (j >= w[i][k]) $
三、代码
#include <cstdio>
#include <algorithm>
using namespace std;
int n, v, num[105], w[105][105], c[105][105], dp[105];
int main() {
scanf("%d %d", &n, &v);
for (int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
for (int j = 1; j <= num[i]; j++) {
scanf("%d %d", &w[i][j], &c[i][j]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = v; j >= 0; j--) {
for (int k = 1; k <= num[i]; k++) {
if (j >= w[i][k]) dp[j] = max(dp[j], dp[j - w[i][k]] + c[i][k]);
}
}
}
printf("%d", dp[v]);
return 0;
}