AcWing 7. 混合背包问题

题目传送门

  • 完全背包
    不是真正意义的无数量上限,而是受限于整体的体积\(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;
}
原文地址:https://www.cnblogs.com/littlehb/p/15684873.html