線性動態規劃--01揹包變形
洛谷p1064
帶有附件的揹包問題,它屬於01揹包的變式。
這題還好,每一個物品最多隻有兩個附件,那麼我們在對主件進行揹包的時候,決策就不再是兩個了,而是五個。
還記得01揹包的決策是什麼嗎?
1.不選,然後去考慮下一個
2.選,揹包容量減掉那個重量,總值加上那個價值。
這個題的決策是五個,分別是:
1.不選,然後去考慮下一個
2.選且只選這個主件
3.選這個主件,並且選附件1
4.選這個主件,並且選附件2
5.選這個主件,並且選附件1和附件2.
這個。。很好想吧。。
我們知道,01揹包的狀態轉移方程(已使用滾動陣列優化)是f[j] = max(f[j],f[j-w[i]]+c[i]),那麼,這道題的轉移方程也就不難寫出了。
等等,你得先判斷某個選附件的決策是不是可行的,如果當前的容量還夠放第一個,或第二個,或兩個都選的附件,那麼才能考慮轉移。
當然,不選附件的話就不用判啦,直接01揹包的轉移方程即可。
我們令main_item_w陣列表示某個主件的費用,而main_item_c陣列表示某個主件的價值。
同樣的,用二維陣列annex_item_w表示某個附件的費用,annex_item_c表示某個附件的價值,第二維只需要0,1,2這三個數,其中第二維是0的場合表示這個主件i的附件數量,它只能等於0或1或2。第二維是1或者是2的值代表以i為主件的附件1或者附件2的相關資訊(費用 價值)。這些陣列的資訊應該在讀入時處理好,具體詳見程式碼。
這樣,狀態轉移方程就是四個。
不選附件的①:f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]);
選附件1的②:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);
選附件2的③:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);
選附件1和附件2的④:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);
已經滾動掉了第一維,道理和正常向的01揹包都是一樣的,即只有i和i-1有關係,但是這個規律在迴圈中已經滿足了所以完全沒必要記錄。
目標狀態f[n],輸出就好。
參考程式碼:
#include<bits/stdc++.h>
#define maxn 32005
using namespace std;
int n,m;
int v,p,q;
int main_item_w[maxn];
int main_item_c[maxn];
int annex_item_w[maxn][3];
int annex_item_c[maxn][3];
int f[maxn];
int main(){
cin >> n >> m;
for (int i=1;i<=m;i++){
cin >> v >> p >> q;
if (!q){
main_item_w[i] = v;
main_item_c[i] = v * p;
}
else{
annex_item_w[q][0]++;
annex_item_w[q][annex_item_w[q][0]] = v;
annex_item_c[q][annex_item_w[q][0]] = v * p;
}
}
for (int i=1;i<=m;i++)
for (int j=n;main_item_w[i]!=0 && j>=main_item_w[i];j--){
f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]);
if (j >= main_item_w[i] + annex_item_w[i][1])
f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);
if (j >= main_item_w[i] + annex_item_w[i][2])
f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);
if (j >= main_item_w[i] + annex_item_w[i][1] + annex_item_w[i][2])
f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);
}
cout << f[n] << endl;
return 0;
}