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

题目: 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<iostream>
#include<algorithm>

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<<f[m];

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值