-
完全背包
不是真正意义的无数量上限,而是受限于整体的体积\(V\)与当前物品的体积\(v_i\)的商:\(S_i=V\%v_i\),这样的话,完全背包可以看成多重背包。 -
多重背包
多重背包通过二进制优化可以打包成多个中间包,视为\(01\)背包 -
完全转化为多重->多重通过二进制转化为\(01\)->利用\(01\)模板解决问题
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n; //物品种类
int m; //背包容量
int v[N]; //物品体积
int w[N]; //物品价值
int f[N]; //dp数组
int idx;
int main() {
cin >> n >> m;
//二进制打包
for (int i = 1; i <= n; i++) {
int vi, wi, si;
//体积,价值,个数
cin >> vi >> wi >> si;
if (si == -1)si = 1; //题目中s=-1表示只有1个
else if (si == 0)si = m / vi; //完全背包(其实本质上就是多重背包):最多总体积/该物品体积向下取整
//如果是其它大于0的数字,那么是多重背包
//将完全背包和多重背包利用二进制优化转化为01背包
int k = 1;
while (k <= si) {
v[++idx] = vi * k;
w[idx] = wi * k;
si -= k;
k *= 2;
idx++;
}
//剩余部分独立成包
if (si > 0) {
v[idx] = si * vi;
w[idx] = si * wi;
idx++;
}
}
//01背包
for (int i = 1; i <= idx; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);
//输出
printf("%d", f[m]);
return 0;
}