【學習筆記】多重揹包優化
阿新 • • 發佈:2021-08-09
多重揹包二進位制拆分
思路(重要的點)
-
普通不優化的多重揹包 : 同一個物品需要拆分成多個有相同價值和成本(體積)的物品
-
優化後的多重揹包也是要把一個大物品拆分成多個小物品,只不過拆分方式不同
例:現有一個物品 $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; }