混合背包

题目链接:https://www.acwing.com/problem/content/7/

 

思路:

如果将前面三个背包混合起来,也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包),应该怎么求解呢?

01背包与完全背包的混合
考虑到在01背包和完全背包中给出的伪代码只有一处不同,故如果只有两类物品:一类物品只能取一次,另一类物品可以取无限次,那么只需在对每个物品应用转移方程时,根据物品的类别选用顺序或逆序的循环即可,复杂度是O(VN)。

再加上多重背包
如果再加上有的物品最多可以取有限次,用多重背包中将每个这类物品分成O(log(p[i]))个01背包的物品的方法也已经很优了。当然,更清晰的写法是调用我们前面给出的三个相关过程。代码:

 

struct Node {
    int kind;
    int v,w;
};

std::vector<Node> vec;

int dp[1010];

int main() {
    int n,m;
    std::cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        int v,w,s;
        std::cin >> v >> w >> s;
        if (s == -1) {
            vec.push_back({-1,v,w});
        }
        else if (s == 0) {
            vec.push_back({0,v,w});
        }
        else {
            for (int k = 1;k <= s;k <<= 1) {
                s -= k;
                vec.push_back({-1,v*k,w*k});
            }
            if (s)
                vec.push_back({-1,v*s,w*s});
        }
    }
    for (auto i:vec) {
        if (i.kind == -1) {
            for (int j = m;j >= i.v;j--)
                dp[j] = std::max(dp[j],dp[j-i.v]+i.w);
        }
        else {
            for (int j = i.v;j <= m;j++) {
                dp[j] = std::max(dp[j],dp[j-i.v]+i.w);
            }
        }
    }
    std::cout << dp[m] << std::endl;
    return 0;
}

 

posted @ 2020-02-01 22:43  _Ackerman  阅读(258)  评论(0编辑  收藏  举报