分组背包:
分组背包
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)
1、题目详情:洛谷U280369 分组背包问题
有 N 组物品和一个容量是 V 的背包。每组物品有若干个,同一组内的物品最多只能选一个。每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。输出最大价值。
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int f[N][N];
int s[N], v[N][N], w[N][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 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;
}
思路: 首先判断一个分组当中的一件物品,同01背包一样,此物品存在两种状态,取与不取,若取此物品,则继续判断下一组的第一件物品,若不取此物品,则继续判断本组下一件物品,若该物品为本组最后一件物品,则判断下一组。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
应当先枚举v,再枚举每一个组内物品。(是为了防止一组内的物品被重复选择)
多重背包:
多重背包
n n 种物品, 每种物品有多件, 每种物品的体积和价值不变
m 背包体积
f[i, j]
1. 集合
f[i, j]表示: 从前 i 种物品中选(每种物品有多件), 所选物品总体积不超过j 的所有选法的集合
存的是集合中的某一方案, 这个方案价值max
2. 计算集合
f[i, j]
枚举第 i 种物品选 了 几个
(0i, 1i, 2i, 3i, ... ki)
f[i, j] = max(f[i - 1, j - k*vi] + k*wi, f[i, j])
f[i,j]=max(f[i-1,j],f[i-1,j-vi]+wi,f[i-1,j-2vi]+2wi...f[i-1,si*vi]+si *wi]);
f[i,j-vi]=max(f[i-1,j-vi],f[i-1,j-2vi]+ wi...f[i-1,j-(si-1)vi-vi)+(si-1)wi,f[i-1,j-(si+1)vi]+si*wi)
3. 边界(初始化)
f[0, j] = 0;
f[i,j]
4. 时间 O(n*m*si)
2、题目详情:洛谷U280382 多重背包问题
有 N 种物品和一个容量是 V 的背包。第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。
基本思路: 比如第 i 件物品有 s 个,我可以把相同种类的物品的进行合并。那么我们可以把第 i 件的 s 个物品转换为s种体积各不相同的物品,然后在用01背包的思想,求出最优解!
#include<bits/stdc++.h>
using namespace std;
const int N = 8 * 100, M = 1e4;
int f[N][M];
int v[N], w[N];
int main(){
int n, m;
cin >> n >> m;
int cnt = 0;
for (int i = 1; i <= n; i ++ ){
int a, b, s;
cin >> a >> b >> s;
int k = 0; // 2^k
while (s > k){
if (k == 0) k ++ ;
cnt ++ ;
v[cnt] = k * a;
w[cnt] = k * b;
s -= k;
k *= 2;
}
if (s){
cnt ++ ;
v[cnt] = s * a;
w[cnt] = s * b;
}
}
n = cnt;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ ){
f[i][j] = f[i - 1][j];
if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
cout << f[n][m] << endl;
return 0;
}
多重背包也是一种基本的背包问题模型,其基本特点是:每种物品有一个固定的装入次数上限。
多重背包问题的一般描述为:有N个物品,第i个物品的重量与价值分别为W[i]与P[i]且第i种物品最多有C[i] 件。背包容量为V,试问在每个物品不超过其上限的件数(物品必须保持完整)的情况下,如何让背包装入的物品具有更大的价值总和。
其一般解题思路为:设f[i][j] 表示从编号1~i的物品中挑选任意数量的任意物品放入容量为j的背包中得到的最大价值,那么有 f[i][j]=max { f[i−1][j−k∗w[i]]+k∗v[i] ∣0≤k≤p[i]&k∗w[i]≤j }。
多重背包我们其实可以看成为01背包和完全背包的组合。也可以把多重背包问题只转换成01背包问题。