混合背包
Posted -ackerman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了混合背包相关的知识,希望对你有一定的参考价值。
题目链接: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; }
以上是关于混合背包的主要内容,如果未能解决你的问题,请参考以下文章