题目描述
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0 $<$ N $\leq$ 1000
0 $<$ V $\leq$ 2000
0 $<$ $v_i$, $w_i$, $s_i$ $\leq$ 1000
提示:
本题考查多重背包的二进制优化方法。
样例
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
二进制法优化
该题每种物品有$s_i$种,而非无限种(不同于完全背包),不可用完全背包的优化方式(具体证明见y总视频 算法基础课完全背包的优化 )
由于0~$s_i$中,均可用$2^0$,$2^1$,$2^2$,$\cdots$,$2^k$,$s_i$-$2^k$来组成。
故我们将每种物品用二进制优化为多个01背包,每个01背包里捆绑着不同个数的该种物品,我们只需选或不选即可。
由小及大,这n种物品即可捆绑成一个数量更多的01背包。
C++ 代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10000;
int v[N], w[N];
int f[N];
int cnt;
int n, m;
int main() {
cin >> n >> m;
//优化为01背包,每个背包选或不选
for(int i = 1; i <= n; i ++ ) {
int a, b, c;
cin >> a >> b >> c;
int k = 1;
while(k < c) {
cnt ++ ;
v[cnt] = k * a;
w[cnt] = k * b;
c -= k;
k *= 2;
}
if(c > 0) {
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] << '\n';
return 0;
}