背包DP——多重背包

多重背包也是 0-1 背包的一个变式。与 0-1 背包的区别在于每种物品有 k 个,而非一个。

朴素

直接把相同的每个物品视作各个单独的物品,没有关联,仅条件相同;
转换后直接用01背包的状态转移方程

注意:在大数据下容易爆空间时间

二进制分组优化

与朴素相比,优化利用二进制原理(任意数可以由多个不同 2^j 数的和表示)
把每种物品的数量k分成多个2j,如1,2,4,8,16……;若k非2i,最后剩下的单独成一组

举几个例子

优化后就可以直接用01背包解决

例题

https://www.luogu.com.cn/problem/P1776

宝物筛选

题目描述

终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。

这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。

小 FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小 FF 有一个最大载重为 \(W\) 的采集车,洞穴里总共有 \(n\) 种宝物,每种宝物的价值为 \(v_i\),重量为 \(w_i\),每种宝物有 \(m_i\) 件。小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

输入格式

第一行为一个整数 \(n\)\(W\),分别表示宝物种数和采集车的最大载重。

接下来 \(n\) 行每行三个整数 \(v_i,w_i,m_i\)

输出格式

输出仅一个整数,表示在采集车不超载的情况下收集的宝物的最大价值。

样例 #1

样例输入 #1

4 20
3 9 3
5 9 1
9 4 2
8 1 3

样例输出 #1

47

提示

对于 \(30\%\) 的数据,\(n\leq \sum m_i\leq 10^4\)\(0\le W\leq 10^3\)

对于 \(100\%\) 的数据,\(n\leq \sum m_i \leq 10^5\)\(0\le W\leq 4\times 10^4\)\(1\leq n\le 100\)

Code

点击查看代码
const int maxn = 1e7 + 10;
int dp[maxn], w[maxn], v[maxn], sum[maxn];
int wnew[maxn], vnew[maxn];
void solve() {
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        cin >> w[i] >> v[i] >> sum[i];
        int x = sum[i], j = 1;
        while (x) {
            if (j <= x) {
                x -= j;
                wnew[++cnt] = w[i] * j;
                vnew[cnt]   = v[i] * j;
                j <<= 1;
            }
            else {
                wnew[++cnt] = w[i] * x;
                vnew[cnt]   = v[i] * x;
                break;
            }
        }
    }
    for (int i = 1; i <= cnt; i++) {
        for (int j = m; j >= wnew[i]; j--) {
            dp[j] = max(dp[j], dp[j - wnew[i]] + vnew[i]);
        }
    }

    cout << dp[m];
}
posted @ 2024-06-29 22:52  uanQ  阅读(12)  评论(0编辑  收藏  举报