多重背包的二进制优化

9 篇文章 1 订阅

引言——dp里面的背包问题。多重背包是指每个物品有c[i]个数量,如果普通的进行dp,f[i][v]=max{f[i-1][v-k*c[i]]+ k*w[i]|0<=k<=n[i]},那么会TLE(虽说我也不知道到底是多少…dalao们帮忙说下呗),如果将数量进行二进制拆分时,那么时间复杂度会显著减少( QAQ我也不知道是多少啊啊啊orz,跪求大佬)

1.思想。
将一个数二进制拆分后变为2^0+2^1+2^2…+2^k+(num-2^k).
原理:
1、2、4可以组合出所有小于8的数。
1、2、4、8可以组合出所有小于16的数。
……
例如,一个数10,我可以分成1、2、4、3。这样就将原本的10个价值相同的物品转化为价值不同的4个物品了。(时间复杂度–!!)
2.代码。

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
inline int read()
{
    int p,data=0;
    char ch=0;
    while((ch!='-')&&ch<'0'||ch>'9') ch=getchar();
    if(ch=='-')
    {
        p=-1;
        ch=getchar();
    }
    else
    {
        p=1;
    } 
    while(ch>='0'&&ch<='9')
    {
     data=data*10+ch-'0';
     ch=getchar();
    }    
    return data*p;
}
int volume[110];
int val[110];
int ccount[110];
int dp[51000];
int main()
{
    memset(dp,0,sizeof(0));
    int num,space;
    num=read();
    space=read();
    for(int i=1;i<=num;i++)
    {
        volume[i]=read();
        val[i]=read();
        ccount[i]=read();
    }
    **for(int i=1;i<=num;i++)
    {
        int d1=1;//d1从1 2 4 8开始枚举,当下一个d1大于剩余物品时,就退出,将剩余物品看成一个物品d2
        int d2=ccount[i];
        while(d1<d2)
        {
            for(int j=space;j>=d1*volume[i];j--)
            {
                dp[j]=max(dp[j],dp[j-d1*volume[i]]+val[i]*d1);
            }
            d2-=d1;
            d1*=2;      
        }
        for(int j=space;j>=d2*volume[i];j--)
        {
            dp[j]=max(dp[j],dp[j-d2*volume[i]]+val[i]*d2);
        }
    }**
    cout<<dp[space];
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值