揹包問題之徹底揹包

問題描述
有N中物品和一個容量爲V的揹包,每種物品都有無限件能夠使用。第i中物品的費用是c[i],價值是w[i]。
求將哪些物品放入揹包能夠使這些物品的費用總和不超過揹包容量且價值總和最大。

分析思路
每一個物品都是無限件,也就當取第i件物品的時候,有0件、1件、2件。。。。等等多種狀況。
令f[i,v]表示前i種物品放入一個容量爲v的揹包時候 取得的最大價值。動態轉移方程爲:
           dp[i,v]=max{   dp[i-1][v-k*c[i]]+w[i]   ||  0<=k*c[i] <=v}

# include <stdio.h >
# include <string.h >
int main()
{
    int N,M,c[ 100],w[ 100],dp[ 200][ 200],dp1[ 2000];
    while (scanf( "%d%d", &M, &N) !=EOF)
    {
       //獲取數據
        for( int i = 1;i < =N;i ++)
            scanf( "%d%d", &c[i], &w[i]);

    //數據初始化
        for( int j = 0;j < =M;j ++)
            if(j > =c[ 1]) dp[ 1][j] =w[ 1];
            else        dp[ 1][j] = 0;

    //利用遞推公式
            for( int i = 2;i < =N;i ++)
                for( int j = 0;j < =M;j ++)
                {

                  dp[i][j] =dp[i - 1][j];

                    int max_temp = 0;
                    for( int k = 0;k < =j /c[i];k ++)   //這裏K從1開始也能夠的。由於K=0的狀況也被歸入了dp[i][j]=dp[i-1][j]
                        max_temp =(dp[i - 1][j -k *c[i]] +k *w[i]) >max_temp ?(dp[i - 1][j -k *c[i]] +k *w[i]) :max_temp;
                    dp[i][j] =max_temp;
                }
               
      printf( "%d\n",dp[N][M]);
    }
    return 0;
}


一樣的,這個能夠進行改進。使用一維數組的方式。
for i = 1....N
      for v = 0.....V
           dp[v] =max{ dp[v] , dp[v -c[i]] +w[i]  }
一樣的當v<c[i]的時候dp[v]仍是原來的沒有改變,
這個代碼在改進一下就是
for i = 1.....N
      for v =c[i]......V
            dp[v] ={ dp[v],dp[v -c[i]] +w[i] }

完整的實現
   memset(dp1, 0, sizeof(dp1));

    for( int i = 1;i < =N;i ++)
      for( int j =c[i];j < =M;j ++)
        dp1[j] =dp1[j] >dp1[j -c[i]] +w[i] ?dp1[j] :dp1[j -c[i]] +w[i];

    printf( "%d\n",dp1[M]);

這裏第二層循環v的順序和01揹包是相反的。 在考慮「加選一件第i種物品」這種策略時,卻正須要一個可能已選入第i種物品的子結果f[i][v-c[i]],因此就能夠而且必須採用v=c[i]..V的順序循環。
因此必定要注意01揹包和徹底揹包的區別。




相關文章
相關標籤/搜索