多重背包的两种求解形式

1.将多重背包转化成01背包求解。

   即将物品的数量M按照二进制分解成 M = 1 + 2 + 4 + ... + 2 ^ k + a. 然后对这些物品进行01背包。

   如果没有求具体方案的,我们可以在求解的过程中进行分解,而不保留对应的物品。

   具体代码如下:

 for(int i = 0; i < N; ++i){
        int num = m[i];
        for(int k = 1; num; k <<= 1){
            int mul = min(k,num);
            for(int j = W; j >= w[i] * mul; --j)
                dp[j] = max(dp[j],dp[j - w[i] * mul] + v[i] * mul);
            num -= mul;
        }
    }

2.用单调队列优化多重背包

考虑最原始的多重背包的转移方程:dp[i+1][j] = max(dp[i][j-k * w[i]] + k * v[i] | 0 <= k <= m && j - k * w[i] >= 0)

可以注意到,对于不同的j ,若j mod w[i]的值不一样,则他们之间是相互独立的。

我们先考虑j mod w[i] = 0的情况。我们定义 a[j] = dp[i][j * w[i]].

这样转移方程可以写成:

dp[i+1][(j+k) * w[i]] = max(a[j + k * v[i]],a[j+1] + (k-1) * v[i],...,a[j'] + (j+k-j')) * v[i],...,a[j+k].

但是直接还是无法方便地计算,再做如下的变形 b[j] = a[j] - j * v[i];

dp[i+1][(j+k) * w[i]] = max(b[j],b[j+1],..b[j+k]) + (j+k)* v[i];

这样,就是滑动最小值一样,可以单调队列优化了。

代码如下:

for(int i = 0; i < N; ++i){
    for(int a = 0; a < w[i]; ++a){
        int s = 0, t = 0;
        for(int j = 0; j * w[i] + a <= W; ++j){
            int val = dp[j * w[i] + a] - j * v[i];
            while(h < t && deqv[t - 1] <= val) t--;
            deq[t] = j , deqv[t++] = val;
            dp[j * w[i] + a] = deqv[s] + j * v[i];
            if(deq[s] == j - m[i]) s++;  
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值