背包问题

Posted on 2011-07-29 08:39  continue_n  阅读(937)  评论(0)    收藏  举报

n表示物品的个数,weight[i]表示第i件物品的重,value[i]表示第i件物品的价值
V为背包容量,s[]存放最优解

一:01背包:
每件物品只有一个,只能选或者不选

for( i = 0 ; i < n ; i++)
{
 for( j = V ; j >= weight[i] ; j--)
 {
  s[j] = Max(s[j],s[j-weight[i]]+value[i]);
 }
}

二:完全背包:
每件物品有无限个

初始化时要注意:
如果要求恰好装满背包,那么在初始化时除了s[0]为0其它s[1..V]均设为-∞(求的是最大解,如果求的是最小解,则为∞) 
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将s[0..V]全部设为0。

for( i = 0 ; i < n ; i++){
   for( j = weight[i] ; j <= V ;j++){
      s[j] = Max(s[j], s[ j - weight[i] ] + value[i] );
   }
}

三:多重背包:
每件物品的个数为count[i]个

多重背包模板

#include <cstdio>
#include <memory.h>

 

int V,dp[100000];

 

inline int max(int a,int b)
{
    return a>b ? a : b;
}

 

void ZeroOnePack(int val,int vol)
{
    for(int v=V;v>=vol;v--)
    dp[v]=max(dp[v],dp[v-vol]+val);
}

 

void CompletePack(int val,int vol)
{
    for(int v=vol;v<=V;v++)
    dp[v]=max(dp[v],dp[v-vol]+val);
}

 

void MultiplePack(int val,int vol,int num)
{
    int cnt;
    if(vol*num>=V) CompletePack(val,vol);
    else
    {
        cnt=1;
        while(cnt<num)
        {
            ZeroOnePack(val*cnt,vol*cnt);
            num-=cnt;
            cnt+=cnt;
        }
    }
    ZeroOnePack(val*num,vol*num);
}

四:混合背包:

以上三种背包的混合,有的物品只能取一次,有的物品能取无限次,有的物品能取有限次

五:二维背包:

每件物品要话费两重的代价,比如我们先前考虑重量加上体积或者总物品的个数等等

初始化的问题:

如果是要求恰好装满背包,那么在初始化时除了s[0]为0其它s[1..V]均设为-∞,这样就可以保证最终得到的s[N]是一种恰好装满背包的最优解。

如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
初始化的s数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可 能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

for( i = 0 ; i <= v ; i++){
     s[i][0] = 0;
     for( j = 1 ; j <= m ; j++){
        s[i][j] = -1;
     }
 }
 for( i = 0 ; i < n ; i++){
     for( j = v ; j >= weight[i] ; j--){
       for( k = m ; k > 0 ; k--){
           if( s[j-weight[i]][k-1] != -1 ){
              s[j][k] = Max(s[j][k],s[j-weight[i]][k-1]+value[i]);
           }
        }
     }
  }

六:分组背包:

有n件物品,分为若干组,每组中只能选择一件物品,问可以得到的最大价值

for( i = 0 ; i < n ; i++)  //从第0组到n-1组
  {
     for( k = v ; k >= 0 ; k--)  
     {
        for( j = 1 ; j <= count[i] ; j++ ) //count[i] 表示第i组的个数,j表示i组中的第几个
        {
           if( k >= weight[i][j] )
              s[k] = Max(s[k] , value[i][j] + s[ k-weight[i][j] ] );
        }
     }
  }

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3