题目描述

有 $N$ 组物品和一个容量是 $V$ 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 $v_{ij}$,价值是 $w_{ij}$,其中 $i$ 是组号,$j$ 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式

第一行有两个整数 $N,V$,用空格隔开,分别表示物品组数和背包容量。

接下来有 $N$ 组数据:

  • 每组数据第一行有一个整数 $S_i$,表示第 $i$ 个物品组的物品数量;
  • 每组数据接下来有 $S_i$ 行,每行有两个整数 $v_{ij}$,$w_{ij}$,用空格隔开,分别表示第 $i$ 个物品组的第 $j$ 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。

数据范围

$0 \lt N, V \le 100$
$0 \lt S_i \le 100$
$0 \lt v_{ij}, w_{ij} \le 100$

输入样例

1
2
3
4
5
6
7
8
3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

1
8

题目求解

分组背包问题可以理解为一组为一个物品的$01$背包问题,在双重for循环中加一层循环用于判断选择一组中的哪一个物品是最优解

AC代码

注意:这里的双重循环的顺序问题容易出错,应该对于每一个$j$ 从大到小更新其$f[j]$的值,是先遍历$j$再遍历$k$,否则每遍历一个物品$f[j]$的值表示的不再是上一组循环结束后的结果,导致结果错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 110;
int n, m, s, v[N], w[N], f[N];

int main() {
cin >> n >> m;
for(int i = 0; i < n; i ++) {
cin >> s;
for(int k = 0; k < s; k ++) cin >> v[k] >> w[k];
for(int j = m; j >= 0; j --) {
for(int k = 0; k < s ; k ++) {
if(j >= v[k])
f[j] = max(f[j], f[j - v[k]] + w[k]);
}
}
}
cout << f[m] << endl;
}

写在结尾

至此背包问题相关题目全部完成。$2024/11/4/23:05$