分组背包
其实与01背包类似,不过是从多组物品里面进行选择。
就比如你的背包总容量是m,货架上有n 组物品(每组物品里面 有多种物品,但每种物品只有一件),给出每组物品里, 每件物品的价值, 体积 。 从 n 组物品中选, 每组物品最多选一件物品, 也可以不选。
在不超过背包容量m的条件下 , 如何挑选物品,使得背包的总价值最大。
集合f[i, j]
表示: n 组物品中选, 每组物品最多选一件物品, 也可以不选
总体积不超过 m 的所有选法的集合,属性为max(价值最大)
分析集合f[i,j]的情况:
1.不选 第 i 组的物品
f[i, j] = max(f[i, j], f[i - 1, j])
2.选 第 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)
初始边界: f[0, j] = 0;
例题:分组背包
题目描述
有 N 种物品和一个容量是 V 的背包。
第 i种物品最多有 si件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
实现代码:
#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;
}
多重背包
多重背包其实和完全背包类似,物品数量多件,注意不是无限!
背包总容量是m,货架上有n 种物品(每种物品数量多件),给出每种物品的价值, 体积 。
在不超过背包容量m的条件下 , 如何挑选物品,使得背包的总价值最大。
集合f[i, j]
表示: 从前 i 种物品中选(每种物品有多件), 所选物品总体积不超过 j 的所有选法的集合
存的是集合中价值最大的方案,属性为max 。
分析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)
边界(初始化):f[0, j] = 0;
例题:多重背包
题目描述
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi ,价值是 wi 。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。
输入格式
第一行两个整数,N,V ,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si ,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
实现代码:
#include <iostream>
using namespace std;
const int N = 110;
int n, m;
int f[N][N];
int v[N], w[N], s[N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
cin >> v[i] >> w[i] >> s[i];
for (int i = 1; i <= n; i ++ ) // 物品种类
for (int j = 1; j <= m; j ++ ) // 体积
{
for (int k = 0; k <= s[i] && k * v[i] <= j; k ++ ) // 第 i 种物品选 几件
f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
}
cout << f[n][m] << endl;
return 0;
}