多重揹包問題

來自《挑戰程序設計競賽》

1.題目原文

有n中物品,它們的重量和價值分別是w[i]和v[i]。現在要從中選出一些物品使得總重量不超過W,並且價值的總和最大。不過要求第i中物品最多可以選m[i]個。
數據範圍
1<=n<=100,1<=w[i],v[i]<=100,1<=m[i]<=10000,1<=W<=10000

2.解題思路1

這是一個有個數限制的問題,對於每個物品至多選一個或者可以選任意個的問題我們已經在O(nW)時間內求解。如果使用同樣的方法解答本題,則狀態轉移方程爲:
dp[i][j]:從編號爲0到編號爲i-1,前i個物品總重量不超過j的所有選法中最大可能的價值。
有dp[0][j]=0;dp[i+1][j]=max{dp[i][j-k*w[i]]+k*v[i]|0<=k<=m[i]且j-k*w[i]>=0}。
如果使用這個狀態轉移方程,時間複雜度就是O(nmW)。

3.代碼1

int n,W;
int w[maxn],v[maxn],m[maxn];
int dp[maxn][maxW];

void solve()
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=W;i++){
        dp[0][i]=0;
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<=W;j++){
            for(int k=0;k<=m[i]&&j>=k*w[i];k++){
                dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
            }
        }
    }
    printf("%d\n",dp[n][W]);
}
這個算法時間複雜度較高,無法在規定時間內求解。

4.解題思路2

5.代碼2

6.解題思路3

我們把m[i]分解成如下形式:m[i]=1+2+2^2+……2^k+a(0<=a<2^(k+1))
由於1,2,2^2,……2^k可以表示出0~2^(k+1)-1的所有整數,因此,1,2,2^2,……2^k,a可以表示出0~m[i]的所有整數。因此,我們可以把m[i]個重量和價值分別是w[i],v[i]的物品看成重量和價值分別是w[i]*x,v[i]*x(x=1,2,2^2,……,2^k,a)的k+2個物品,這樣物品的總數就變爲O(nlogm)個,使用一般的01揹包DP可以在O(nWlogm)時間內求出答案。

7.代碼3

int n,W;
int w[maxn],v[maxn],m[maxn];
int dp[maxW];

void solve()
{
    for(int i=0;i<n;i++){
        int num=m[i];
        for(int k=1;num>0;k<<=1){
            int mul=min(k,num);
            for(int j=W;j>=w[i]*mul;j--){
                dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);
            }
            num-=mul;
        }
    }
    printf("%d\n",dp[W]);
}


發佈了119 篇原創文章 · 獲贊 16 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章