首页 > 其他分享 >Acwing 5. 多重背包问题 II

Acwing 5. 多重背包问题 II

时间:2022-12-22 22:22:05浏览次数:51  
标签:多重 cnt good int II 背包 物品 Acwing

二进制优化法

本质: 将多重背包转化为 01背包问题

思路:

暴力法其实相当于把多重背包中的每个物品分成 \(s\) 个物品,所以才需要那么久的时间复杂度,所以现在想一下有没有什么分法,可以通过选这些物品,选几个来表示选 \(s\) 个的所有可能。

这时候就想到了二进制,因为任何实数都可以由二进制数组成。

那么我们就可以把一个物品拆成 \(2^0,2^1,2^2,...,2^k ,(x-2^{k+1} + 1)(k为最大的2^k不大于x的实数)\),\(\log x\) 个物品。

这些物品可以通过组合,组成 \(0-x\) 内的整数(不能漏不能多)

证明

设一个实数为 \(x\) ,拆分成 \(2^0,2^1,2^2,...,2^k,c\) ,( \(k\) 为最大的 \(2^k\) 不大于 \(x\) 的实数),因为 \(k\) 是最大的 \(2^k\) 不大于 \(x\) 的实数,所以可以知道 \(c < 2 ^{k + 1}\) 。

根据二进制可知 \(0\) 到 \((2^{k + 1} - 1)\) 都可以用以上的数组成

上式子 + \(c\) 可得 \(c\) 到 \((2^{k + 1} - 1 + c)\) 也都可以用以上数组成。因为 \(2^{k + 1}-1+c\) 为可以凑到的最大值,所以$ 2^{k + 1} - 1 + c = S \Rightarrow c = S - (2^{k + 1} - 1)$

现在已知 \(0 -( 2^{k + 1} - 1)\) 和 \(c - S\) 两端都可以由以上数拼接起来,现在的问题就是,这两段合在一起的时候,中间有无空缺。

如果有空缺的话,\(c > 2 ^{k + 1} - 1\) 即, \(c \ge 2^{k + 1}\)。

显然与开始得到的 \(c < 2 ^{k + 1}\) 相矛盾,可得 \(0-S\) 中的任何一个数都可以拼接起来。

时间复杂度: \(O(物品数*背包的体积*log选法) = O(N*V*logS)\)

这个时间复杂度可以过这个多重背包:5. 多重背包问题 II - AcWing题库

实现:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int f[N], n, m;
struct Good
{
    int w, v;
} good[N];
int main()
{
    scanf("%d%d", &n, &m);
    // 遍历物品
    while (n--)
    {
        int v, w, s;
        scanf("%d%d%d", &v, &w, &s);
        // 记录分成多少块
        int cnt = 1;
        for (int i = 1; i <= s; i *= 2)
        {
            // 分成2^k次方的时候
            // 新物品的体积和价值 = 选的个数 *单个的体积和价格
            good[cnt].v = i * v;
            good[cnt++].w = i * w;
            s -= i;
        }

        // 最后一个物品
        if (s > 0)
        {
            good[cnt].v = s * v;
            good[cnt++].w = s * w;
        }

        // 现在相当于变成了01背包
        // 遍历物品
        for (int i = 1; i < cnt; i++)
            // 遍历体积,由于滚动了一维,所以一定要逆序遍历
            for (int j = m; j >= good[i].v; j--)
                f[j] = max(f[j], f[j - good[i].v] + good[i].w);
    }
    printf("%d\n", f[m]);
    return 0;
}

标签:多重,cnt,good,int,II,背包,物品,Acwing
From: https://www.cnblogs.com/zxr000/p/16999729.html

相关文章

  • AcWing342. 道路与航线
    原题链接解题思路这题用\(SPFA\)会被卡,所以我们不能用\(SPFA\)但是观察数据我们可以发现对于道路,\(0≤C_i≤10^{5}\)所以对于每个连通块(内部不存在航线),我们可以用\(Di......
  • Acwing 4. 多重背包问题
    4.多重背包问题I-AcWing题库有\(N\)种物品和一个容量是\(V\)的背包。第\(i\)种物品最多有\(s_i\)件,每件体积是\(v_i\),价值是\(w_i\)。求解将哪些物品装入......
  • Acwing 第 77 场周赛 ABC(*)
    4716.进球题目大意:整场比赛双方一共打进了n个进球,进球多的一方将收获最终的胜利。请你根据进球纪录,判断哪支球队最终获胜。保证不存在平局。输入样例1:1ABC......
  • Codeforces Round #840 (Div. 2) and Enigma 2022 - Cybros LNMIIT(持续更新)
    Preface有史以来打的最爆炸的一场,只写了AB一个原因是最近由于得了新冠导致疏于锻炼,脑子和手都有点不在状态另一个原因就是没去想C去开一眼感觉很naive的D(事实确实很naiv......
  • C++| 1-RAII
     RAII,完整的英文是ResourceAcquisitionIsInitialization,是C++所特有的资源管理方式。RAII依托栈和析构函数,来对所有的资源——包括堆内存在内——进行管理。对......
  • 2019 TRIUMPH ROCKET III ROADSTER SERVICE LAMP RESET
    Background:A2019TRIUMPHROCKETIIIROADSTER,itsmaintenancetimeisup,thedashboardshowsawrenchformaintenancetips.PreparationPreparation: OBDS......
  • 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数
    题目内容给定一个非负整数n ,请计算0到n之间的每个数字的二进制表示中1的个数,并输出一个数组。说明:0<=n<=105解题思路1直接运用内置函数bin()和count()将......
  • AcWing787.归并排序
    题目描述给定你一个长度为\(n\)的整数数列。请你使用归并排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式输入共两行,第一行包含整数\(......
  • pgpool_II节点状态问题(pgpool_status)
    环境:OS:Centos7PG:14pgpool:4.4通过vip登录发现主节点状态一直是down,重启该节点的pgpool_II也没有用[postgres@pg2pgpool-II]$psql-h192.168.1.199-p9999-Up......
  • 背包初始化细节
    背包问题初始化的细节刚开始是最简单的01背包,这个需要我们求的是从前i个物品里面选,体积不超过j的问题。然后就是从i个物品里面选,体积恰好是j的一个方案。同时还有从前i......