栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【题解】二进制优化的多重背包问题

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【题解】二进制优化的多重背包问题

题目: https://www.acwing.com/problem/content/5/

题意: 裸多重背包,但是题目数据范围较大。三重循环纯朴素解法会超时。
思路:

  1. 为什么会超时? 对于每种物品,如果每次在遍历每种物品和每个体积的时候都枚举一遍物品数量,那么时间复杂度会到O(n^3),n=1000时,计算量就到了10亿次的级别,而c++一秒只能算1亿次,所以必须考虑优化。
  2. 怎么优化? 对于每个物品如果暴力枚举所有数量会超时,那么考虑将一部分物品分组。我们可以将物品按二进制的方式进行分组:1,2,4,8,,,2^k,C。前k+1项很好理解,分别是2的0~k次方,C是什么?因为我们要通过二进制分组的方式,表达出某个物品的任意数量,那么分组之后的总和也应该等于该物品的数量,C就是该物品的总数量依次减去前k+1项后的值。
  3. 为什么可以这样优化? 首先我们必须了解一点,二进制分组的方式可以表示出所有可能,比如:1,2,4,8。是可以表示出0~15任意的一个数的。 为什么要强调这一点?因为二进制分组同样遍历了所有的可能。 那么二进制和普通的枚举区别在哪? 二进制的遍历是在不同体积下体现的,而普通的枚举则是每种体积都会枚举一次。
    概括而言:二进制将体积的变化与物品不同数量的枚举结合在了一起。

代码:

#include
#include

using namespace std;
const int N=25000,M=2000;

int n,m;
int v[N],w[N];
int f[M];

int main()
{
    cin>>n>>m;
    int cnt=0;//表示将数据处理为01背包问题后,总物品的个数
    for(int i=1;i<=n;++i)
    {
        int a,b,c;
        cin>>a>>b>>c;
        int k=1;
        while(k<=c)
        {
            cnt++;
            v[cnt]=a*k;
            w[cnt]=b*k;
            c-=k;
            k*=2;
        }
        if(c)
        {
            cnt++;
            v[cnt]=a*c;
            w[cnt]=b*c;
        }
    }
    n=cnt;//总物品的数量变为cnt个

    for(int i=1;i<=n;++i)
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);

    cout<
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/938229.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号