开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情
本题为分组背包的模板题。
分组背包
题目描述
有 组物品和一个容量是 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 ,价值是 ,其中 是组号, 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 ,用空格隔开,分别表示物品组数和背包容量。
接下来有 组数据:
- 每组数据第一行有一个整数 ,表示第 个物品组的物品数量;
- 每组数据接下来有 行,每行有两个整数 ,用空格隔开,分别表示第 个物品组的第 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例
8
题目分析
这是一道分组背包的板子题。
在我看来,我认为可以用01背包的思想帮助理解分组背包。
在01背包中,每件物品有两种状态,选或不选。同样的,在分组背包中,每组物品也同样有两种状态,一是不选,二是选择其中最优的物品,而这个状态又有 个子状态,即选择第 件物品。
我们设 为前 组物品中总体积为 的最优解。
同样也可以优化到一维,复杂度为
Accept代码 O(n^2v)
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int v[N][N], w[N][N];
int s[N], f[N];
int main()
{
int n, m;
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 k = m; k; k --)
for (int j = 1; j <= s[i]; j ++) // 此层循环和上层不能交换
if (k >= v[i][j]) f[k] = max(f[k], f[k - v[i][j]] + w[i][j]);
cout << f[m];
return 0;
}