問題
二維費用的揹包問題是指:對於每件物品,具有兩種不同的費用;選擇這件物品必須同時付出這兩種代價;對於每種代價都有一個可付出的最大值(例如:揹包容量)。問怎樣選擇物品可以得到最大的價值。設這兩種代價分別爲代價1和代價2,第i件物品所需的兩種代價分別爲a[i]和b[i]。兩種代價可付出的最大值(兩種揹包容量)分別爲V和U。物品的價值爲w[i]。
一、算法
費用加了一維,只需狀態也加一維即可。設 f[i][v][u] 表示前 i 件物品付出兩種代價分別爲 v 和 u 時可獲得的最大價值。狀態轉移方程就是:
如前述方法,可以只使用二維的數組:當每件物品只可以取一次時變量v和u採用逆序的循環,當物品有如完全揹包問題時採用順序的循環。當物品有如多重揹包問題時拆分物品。
二、物品總個數的限制
有時,“二維費用”的條件是以這樣一種隱含的方式給出的:最多隻能取M件物品。這事實上相當於每件物品多了一種“件數”的費用,每個物品的件數費用均爲1,可以付出的最大件數費用爲M。換句話說,設f[v][m]表示付出費用v、最多選m件時可得到的最大價值,則根據物品的類型(01、完全、多重)用不同的方法循環更新,最後在f[0..V][0..M]範圍內尋找答案。
另外,如果要求“恰取M件物品”,則在f[0..V][M]範圍內尋找答案。
三、複數域上的揹包問題
另一種看待二維揹包問題的思路是:將它看待成複數域上的揹包問題。
也就是說,揹包的容量以及每件物品的費用都是一個複數。而常見的一維揹包問題則是實數域上的揹包文圖。(注意:上面的話不嚴謹,因爲事實上只是我們處理的都是整數而已。)所以說,一維揹包的種種思想方法,往往可以應用於二維揹包問題的求解中,因爲只是數域擴大了而已。
四、例題
代碼:
#include <iostream>
#include <algorithm>
using namespace std;
#define N 105
int f[N][N];
int main() {
int n,V,W; cin >> n >> V >>W;
int v,m,w;
for(int i = 0;i < n;i++) {
scanf("%d%d%d",&v,&m,&w);
for(int k = V;k >= v;k--) {
for(int u = W;u >= m;u--) {
f[k][u] = max(f[k][u],f[ k-v ][ u-m ] + w);
}
}
}
cout << f[V][W] << endl;
return 0;
}