多重背包
有
N
种物品和一个容量是
V
的背包。
第 i
种物品最多有 si
件,每件体积是 vi
,价值是 wi
。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V
用空格隔开,分别表示物品种数和背包容积。
接下来有N
行,每行三个整数 vi,wi,si
用空格隔开,分别表示第i
种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N≤1000
0<V≤20000
0<vi,wi,si≤20000
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
解题思路
朴素版
同完全背包朴素版,将其中的k换成s,于是有
#include <iostream>
using namespace std;
int f[1010][20010];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
int v, w, s;
cin >> v >> w >> s;
for(int j = 0; j <= m; j ++)
{
f[i][j] = f[i - 1][j];
for(int k = 1; k <= s && k * v <= j; k ++)
f[i][j] = max(f[i][j], f[i - 1][j - v * k] + w * k);
}
}
cout << f[n][m] << endl;
return 0;
}
优化一维
同01背包,用到上一层的结果,需要逆序
#include<iostream>
using namespace std;
int f[20010];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i ++)
{
int v, w, s;
cin >> v >> w >> s;
for(int j = v; j <= m; j ++)
for(int k = 1; k <= s && k * v <= j; k ++)
f[j] = max(f[j], f[j - k * v] + k * w);
}
cout << f[m] << endl;
return 0;
}
二进制优化
原理,一个数可以由二进制表示,而将每个物品的数量拆分为二进制,每个二进制的位数可以是选或不选。
比如将10
拆分为1、2、4、3
在这上面再做一个01
背包
设需要拆分的数为x
,则将其拆分为20,21,22,……,2k,C(其中2k <= x < 2k + 1,C >= 0)
二进制优化代码如下
#include <iostream>
using namespace std;
//20000 二进制为 15位,再加一个C按16算,且物品数量N<=1000,故存储拆分为二进制的数量为16000足以。
const int N = 16000;
int v[N], w[N];
int f[20010];
int main()
{
int n, m;
cin >> n >> m;
int cnt = 0; //计数
for(int i = 0; i < n; i ++)
{
int a, b, c; //体积、价值、数量
cin >> a >> b >> c;
for(int j = 1; j <= c; j <<= 1)
{
cnt ++;
v[cnt] = j * a;
w[cnt] = j * b;
c -= j;
}
if(c)
{
cnt ++;
v[cnt] = c * a;
w[cnt] = c * b;
}
}
n = cnt;
for(int i = 1; i <= n; i ++)
for(int j = m; j >= v[i]; j --)
f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << endl;
return 0;
}