1. 程式人生 > 其它 >【學習筆記】多重揹包優化

【學習筆記】多重揹包優化

 多重揹包二進位制拆分

思路(重要的點)

  • 普通不優化的多重揹包 : 同一個物品需要拆分成多個有相同價值和成本(體積)的物品

  • 優化後的多重揹包也是要把一個大物品拆分成多個小物品,只不過拆分方式不同

  例:現有一個物品 $A$,每個體積為 $4$,價值為 $2$,共有 $9$ 個這樣的物品 $A$。這種物品有 $2$ 種拆分方式:

    1.拆分成體積為 $4$,價值為 $2$ 的 $9$相同的物品 $A$(不優化),再用 01 揹包去做(每一個小物

品都可以選/不選)

    2.拆分成 $4$ 個小物品。第一個:體積為 $4$(1$\times$4),價值為 $2$($1\times

2$)(由$2^0$個物品 A 組成)

             第二個:體積為 $8$($2\times4$),價值為 $4$($2\times2$)(由$2^1$個物品 A 組成)

             第三個:體積為 $16$($4\times4$),價值為 $8$($2\times4$)(由$2^2$個物品 A 組成)

             第四個:體積為 $8$($2\times4$),價值為 $4$($2\times2$)(由$2^3$個物品 A 組成)

    由這4個小物品可以表示出 $1\backsim9$ 其他不是 $2$ 的次冪的個數的物品(如 $3$ = 第一個+第二個)

            拆分完,再去寫 01 揹包程式碼即可

程式碼

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,V;//n種物品,容量是V的揹包
int v[10000],w[10000],s[10000];
int new_c[10000],new_w[10000];
//新的體積,新的價值 
int tot=1;
int dp[10000];
int main(){
    cin >> n >> V;
    for(int i=1; i<=n; i++){
        cin >> v[i] >> w[i] >> s[i];
    }
    for(int i=1; i<=n; i++){//每一個物品 
        for(int j=1; j<=s[i]; j<<=1){//二進位制拆分 
            s[i] -= j;//減去拆分出來的
            new_c[tot] = j*v[i];
            new_w[tot] = j*w[i];
            tot++;
        }
        if(s[i]){
            //還有剩餘,單獨組成一個大物品 
            new_c[tot] = s[i]*v[i];
            new_w[tot] = s[i]*w[i];
            tot++;
        }
    }
    //01揹包 
    for(int i=1; i<tot; i++){
        for(int j=V; j>=new_c[i]; j--){
            dp[j] = max(dp[j],dp[j-new_c[i]]+new_w[i]);
        }
    }
    cout << dp[V];
    return 0;
}