题目描述
有 N 组物品和一个容量是 V 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vij ,价值是 wij ,其中 i 是组号,j 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,V ,用空格隔开,分别表示物品组数和背包容量。
接下来有 N 组数据:
每组数据第一行有一个整数 Si,表示第 i 个物品组的物数量; 每组数据接下来有 Si 行,每行有两个整数 vij, wij,用空格隔开,分别表示第 i 个物品组的第 j个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
输入输出样例
输入
3 5 2 1 2 2 4 1 3 4 1 4 5输出
8说明/提示
0<N,V≤100
0<Si≤100
0<vij,wij≤100
代码:
/*
分组背包
n , m
n 物品组
m 背包体积
每组物品里面, 有多种物品,(每种物品只有一件)
给出每组物品里, 每件物品的价值, 体积
求 从 n 组物品中选, 每组物品最 多选一件物品, 也可以不选
总体积不超过 m , 总价值最大
f[i, j]
f[i, j] = k;
1. 集合
表示: n 组物品中选, 每组物品最 多选一件物品, 也可以不选
总体积不超过 m 的所有选法的集合
(属性, 数)存的数是这个集合中的某一个方案, 这个方案总价值最大
max(价值)
2. 计算集合
f[i, j] ---> 包含的子集, 只要找 到所有子集取 Max
在这个题里面, 每个子集就是一种方案
max(1, 2, 3, 4, ...i);
f[i, j]
不选 第 i 组的物品
f[i, j] = max(f[i, j], f[i - 1, j])
选 第 i 组的物品
选第 i 组的哪一个物品
k: 第 i 组 物品中第 k 个物品
f[i, j] = max(f[i - 1, j - vik] + wik, f[i, j])
f[i,j] = max(f[i-1,j], f[i-1,j-vi1]+wi1, f[i-1,j-vi2] +wi2...f[i-1,j-vik] + wik)
f[i,j-vi1] = max(f[i-1,j-vi1],f[i-1,j-2vi1]+wi1, f[i-1,j-vi1-vi2]+wi2...f[i-1,j-vi1-vik]+wik)
3. 边界: f[0, j] = 0;
4. O(n^3)
*/
#include <iostream>
using namespace std;
const int N = 110;
int n, m;
int f[N][N];
int s[N], v[N][N], w[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++){
cin >> s[i];
for (int j = 1; j <= s[i]; j++)
cin >> v[i][j] >> w[i][j];
}
for (int i = 1; i <= n; i++) // 物品组
for (int j = 1; j <= m; j++){ // 体积
f[i][j] = f[i - 1][j];
for (int k = 1; k <= s[i]; k++) // 每组物品中的每个物品
if (v[i][k] <= j)
f[i][j] = max(f[i - 1][j - v[i][k]] + w[i][k], f[i][j]);
}
cout << f[n][m] << endl;
return 0;
}