Codeforces 106C Buns - 多重背包 - 二进制拆分

多重背包可以拆分为01背包来做,最暴力的想法是把每类物品拆成一个个的,然后拆分后的物品各自为一类,做01背包。然而这样太慢了,我们可以用二进制(倍增)来优化拆分。

比如说我们有
1
10
100
1000
10000
这些二进制数,他们代表1, 2, 4, 8, 16
那么这些数可以组合出1~31之间所有的数
所以把物品倍增拆分,一样可以得到正确的答案。

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1010;
struct Bread{
    int mx, v, w;//最大个数,价值,花费/重量 
}bre[MAXN];
int n,m,c0,d0,ans,sum;
int f[MAXN];
int main() {
    cin >> n >> m >> c0 >> d0;
    bre[0].mx = n/c0,bre[0].v = d0,bre[0].w = c0;
    for(int i=1; i<=m; i++) {
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        bre[i].mx = a/b;
        bre[i].v = d;
        bre[i].w = c;   
    }
    for(int i=0; i<=m; i++) {
        int a[22], t = 0, sum = 0;//循环到20 开到22
        for(int k=0; k<=20; k++) {
            sum += 1<<k;
            if(sum > bre[i].mx) {
                sum -= 1<<k;
                break;
            }
            a[++t] = (1<<k);
        }
        a[++t] = bre[i].mx - sum; //二进制划分后剩下的部分
        for(int k=1; k<=t; k++) {
            int vk = bre[i].v*a[k];
            int wk = bre[i].w*a[k];
            for(int j=n; j>=wk; j--) {
                f[j] = max(f[j],f[j-wk]+vk);
            }
        }
    }
    cout << f[n];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值