多重揹包的兩種求解形式

1.將多重揹包轉化成01揹包求解。

   即將物品的數量M按照二進制分解成 M = 1 + 2 + 4 + ... + 2 ^ k + a. 然後對這些物品進行01揹包。

   如果沒有求具體方案的,我們可以在求解的過程中進行分解,而不保留對應的物品。

   具體代碼如下:

 for(int i = 0; i < N; ++i){
        int num = m[i];
        for(int k = 1; num; 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;
        }
    }

2.用單調隊列優化多重揹包

考慮最原始的多重揹包的轉移方程:dp[i+1][j] = max(dp[i][j-k * w[i]] + k * v[i] | 0 <= k <= m && j - k * w[i] >= 0)

可以注意到,對於不同的j ,若j mod w[i]的值不一樣,則他們之間是相互獨立的。

我們先考慮j mod w[i] = 0的情況。我們定義 a[j] = dp[i][j * w[i]].

這樣轉移方程可以寫成:

dp[i+1][(j+k) * w[i]] = max(a[j + k * v[i]],a[j+1] + (k-1) * v[i],...,a[j'] + (j+k-j')) * v[i],...,a[j+k].

但是直接還是無法方便地計算,再做如下的變形 b[j] = a[j] - j * v[i];

dp[i+1][(j+k) * w[i]] = max(b[j],b[j+1],..b[j+k]) + (j+k)* v[i];

這樣,就是滑動最小值一樣,可以單調隊列優化了。

代碼如下:

for(int i = 0; i < N; ++i){
    for(int a = 0; a < w[i]; ++a){
        int s = 0, t = 0;
        for(int j = 0; j * w[i] + a <= W; ++j){
            int val = dp[j * w[i] + a] - j * v[i];
            while(h < t && deqv[t - 1] <= val) t--;
            deq[t] = j , deqv[t++] = val;
            dp[j * w[i] + a] = deqv[s] + j * v[i];
            if(deq[s] == j - m[i]) s++;  
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章