码迷,mamicode.com
首页 > 其他好文 > 详细

背包问题

时间:2015-03-18 23:05:53      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:

背包问题

目前已经学了三种背包问题,是时候整理一下模版了

 

01背包

这是最基础的背包问题,即每件物品只能取一次,问背包能装的不超过容量的最大价值

方程:dp[i][j]=max{dp[i-1][j],dp[i-1][j-w[i]]+val[i]}(j>=w[i])

    边界:dp[i][j]=dp[i-1][j](j<w[i]),dp[0][j]=0;

空间优化:由于dp[i][]只与dp[i-1][]有关,所以可以用滚动数组或迭代成一维数组进行空间优化

  滚动数组:让i%2即可,就不贴代码了

  迭代转为一维数组:dp[j]=max(dp[j],dp[j-w[i]]+val[i]),此时j必须逆序遍历,关于为什么逆序在另一篇博客http://www.cnblogs.com/--560/p/4340764.html已经介绍的很清楚了,就不过多叙述了,这里只给代码

技术分享
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++){
      for(int j=M;j>=0;j--){
            if(j-w[i]>=0) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
      }
}

/* 由于j>=w[i],所以上述代码也可以这样写  */

memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++){
      for(int j=M;j>=w[i];j--){
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
      }
}
01背包

 

完全背包

即有n种物品,每种物品有无限个,还是问背包能装的不超过容量的最大价值

方程:dp[j]=max{dp[j-w[i]]+val[i],dp[j]} 方程和01背包表面上一样,但其实不一样,j必须顺序遍历;在另一篇博客已经解释的很清楚了,就不解释了,附链接http://www.cnblogs.com/--560/p/4345855.html

技术分享
dp[0]=0;
for(int i=1;i<=N;i++){
    for(int j=M;j>=0;j--){
        if(j-w[i]>=0) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
}

/* 同样也可以写成这样 */
dp[0]=0;
for(int i=1;i<=N;i++){
    for(int j=M;j>=w[i];j--){
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
}
完全背包

 

多重背包

即每种物品数量有限,问题同上

方法:用二进制优化并转为01背包,懒得写了,直接看下面的代码吧

技术分享
void ZeroOnePack(int weight,int val)
{
    for(int i=cash;i>=weight;i--){
        dp[i]=max(dp[i],dp[i-weight]+val);
    }
}

void CompletePack(int weight,int val)
{
    for(int i=weight;i<=cash;i++){
        dp[i]=max(dp[i],dp[i-weight]+val);
    }
}

void MultiPack(int weight,int val,int amount)
{
    if(weight*amount>=cash) CompletePack(weight,val);//如果超过限制,当完全背包处理
    else{                //否则用二进制优化并转为01背包处理
        int k=1;
        while(k<amount){//按k=1,2,4,...的顺序分解amount,对分解后的部分按01背包处理
            ZeroOnePack(k*weight,k*val);
            amount-=k;
            k*=2;
        }
        ZeroOnePack(amount*weight,amount*val); //剩下部分也按01背包处理
    }
}

int main()
{
    while(cin>>cash>>N){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=N;i++){
            cin>>n[i]>>D[i];
            MultiPack(D[i],D[i],n[i]);
        }
        cout<<dp[cash]<<endl;
    }
    return 0;
}
多重背包

 

背包问题

标签:

原文地址:http://www.cnblogs.com/--560/p/4348813.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!