问题的描述
分组背包问题
有
N
N
N组物品和一个容量是
V
V
V的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是
v
i
j
v_{ij}
vij,价值是
w
i
j
w_{ij}
wij,其中
i
i
i是组号,
j
j
j是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
数据具体内容
输入格式
第一行有两个整数
N
,
V
N,V
N,V,用空格隔开,分别表示物品组数和背包容量。
接下来有
N
N
N组数据:
每组数据第一行有一个整数
S
i
S_i
Si,表示第
i
i
i个物品组的物品数量;
每组数据接下来有
S
i
S_i
Si行,每行有两个整数
v
i
j
,
w
i
j
v_{ij},w_{ij}
vij,wij,用空格隔开,分别表示第
i
i
i个物品组的第
j
j
j个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
0
<
N
,
V
≤
100
0<N,V≤100
0<N,V≤100
0
<
S
i
≤
100
0<S_i≤100
0<Si≤100
0
<
v
i
j
,
w
i
j
≤
100
0<v_{ij},w_{ij}≤100
0<vij,wij≤100
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例
8
动态规划
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 110;
int n, m;
int f[N], v[N], w[N];
int main(){
cin >> n >> m;
for(int i = 0; i < n; i ++ ){
int s;
cin >> s;
for(int j = 0; j < s; j ++ ) {
cin >> v[j] >> w[j];
}
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;
return 0;
}
解题逻辑梳理
- 分组背包问题是01背包的扩展,在01背包的问题上添加了在同组的多个物品中,选择其中一个的步骤。因此可以将问题考虑为,先看是否选择第 i i i组中的物品(01背包问题),然后看选择第 i i i组中的哪一个物品。
- 那么就有状态转移关系式 f [ i ] [ j ] = { ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v [ k ] ] + w [ k ] ) ∣ k = 0 , 1 , . . . , s } f[i][j] = \{(f[i- 1][j], f[i-1][j - v[k]] + w[k])| k = 0, 1, ..., s\} f[i][j]={(f[i−1][j],f[i−1][j−v[k]]+w[k])∣k=0,1,...,s},即不取 i i i组中的物品,和取 i i i组中的物品,且取"物品一"or"物品二"or…。
- 想要取物品必须满足背包能够装下物品
k
k
k的条件,即
j
>
=
v
[
k
]
j >= v[k]
j>=v[k]
- 采用01背包的二维优化为一维方法,将解答方案优化为一维。