-----edit by zhusenlin hdu
本人博文《揹包問題——「01揹包」詳解及實現(包含揹包中具體物品的求解)>>中已談過01揹包,這裡再重寫一下01揹包的動態規劃狀態及狀態方程:
設揹包容量為v,一共n件物品,每件物品體積為c[i],每件物品的價值為w[i]
1) 子問題定義:f[i][j]表示前i件物品中選取若干件物品放入剩餘空間為j的揹包中所能得到的最大價值。
2) 根據第i件物品放或不放進行決策
最優方案總數這裡指物品總價值最大的方案數。
我們設g[i][j]代表f[i][j]的方案總數,那麼最總結果應該是g[n][v]。我們初始化g為1,因為對每個f[i][j]至少應該有一種方案,即前i件物品中選取若干件物品放入剩餘空間為j的揹包使其價值最大的方案數至少為1,因為f[i][j]一定存在。
下面開始分析怎麼求g[i][j]。對於01揹包來說:
如果f[i][j]=f[i-1][j]且f[i][j]!=f[i-1][j-c[i]]+w[i]說明在狀態[i][j]時只有前i-1件物品的放入才會使價值最大,所以第i件物品不放入,那麼到狀態[i][j]的方案數應該等於[i-1][j]狀態的方案數即g[i][j]=g[i-1][j];
如果f[i][j]=f[i-1][j-c[i]]+w[i] 且f[i][j]!=f[i-1][j]說明在狀態[i][j]時只有第i件物品的加入才會使總價值最大,那麼方案數應該等於[i-1][j-c[i]]的方案數,即g[i][j]=g[i-1][j-c[i]];
如果f[i][j]=f[i-1][j-c[i]]+w[i] 且f[i][j]=f[i-1][j]則說明即可以通過狀態[i-1][j]在不加入第i件物品情況下到達狀態[i][j],又可以通過狀態[i-1][j-c[i]]在加入第i件物品的情況下到達狀態[i][j],並且這兩種情況都使得價值最大且這兩種情況是互斥的,所以方案總數為g[i][j]=g[i-1][j-c[i]]+ g[i-1][j]。
經過上面的分析,得出下述偽**:
f[0] ← 0
f[0] ← 0
g[ ] ← 1
for i ← 1 to n
do for j ← 1 to v
f[i][j] ← f[i-1][j]
g[i][j] ← g[i-1][j]
if (j >= c[i])
if (f[i][j] < f[i-1][j-c[i]]+w[i])
then f[i][j] ← f[i-1][j-c[i]]+w[i]
g[i][j] ← g[i-1][j-c[i]]
else if (f[i][j] = f[i-1][j-c[i]]+w[i])
then g[i][j] ← g[i-1][j]+g[i-1][j-c[i]]
return f[n][v] and g[n][v]
上述方法在儲存狀態f及g時需要o(nv)的空間複雜度,下面我們對空間復制度進行優化。
壓縮空間複雜度為o(v)
f[i][j]與g[i][j]只分別與f[i-1]和g[i-1]的狀態有關,所以我們可以用兩個一維陣列f和g來替換二維陣列f和g。具體思想請看博文
《揹包問題——「01揹包」詳解及實現(包含揹包中具體物品的求解)>>
下面直接給出偽**:
f ← 0
g ← 1
for i ← 1 to n
do for j ← v to c[i]
if (f[j] < f[j-c[i]]+w[i])
then f[j] ← f[j-c[i]]+w[i]
g[j] ← g[j-c[i]]
else if (f[j] = f[j-c[i]]+w[i])
then g[j] ← g[j]+g[j-c[i]]
return f[v] and g[v]
下面對資料表給出以上兩種不同空間複雜度的詳細**:
揹包資料表(揹包容量10)
物品號i12
345體積c32
545價值w55
101010
#include #include #include "createarray.h" //該標頭檔案是動態建立和銷毀二維陣列,讀者自己實現
using namespace std;
時間複雜度o(vn),空間複雜度為o(vn):
int package01optimal(int weight, int value, int nlen, int ncapacity)
else if(maxvaluetable[i][j] == (maxvaluetable[i-1][j-weight[i-1]]+value[i-1]))
}} }
cout << endl << "optimalcount:" << optimaltable[nlen][ncapacity] << endl;
int nret = maxvaluetable[nlen][ncapacity];
destroytwodimarray(maxvaluetable,nlen+1); //銷毀最大價值表,防止記憶體洩露
destroytwodimarray(optimaltable,nlen+1); //銷毀最優方案總數表,防止記憶體洩露
return nret;
}
時間複雜度o(vn),空間複雜度為o(v):
int package01optimal_compress(int weight, int value, int nlen, int ncapacity)
else if(maxvaluetable[j] == maxvaluetable[j-weight[i]]+value[i])
optimaltable[j] = optimaltable[j-weight[i]]+optimaltable[j];
} }cout << endl << "optimalcount:" << optimaltable[ncapacity] << endl;
int nret = maxvaluetable[ncapacity];
delete optimaltable;
delete maxvaluetable;
return nret;
}
測試**:
int main()
; //int value = ;
int weight = ;
int value = ;
int ncapacity = 10;
cout << "maxvalue:" << package01optimal(weight,value,sizeof(weight)/sizeof(int),ncapacity) << endl;
cout << "maxvalue:" << package01optimal_compress(weight,value,sizeof(weight)/sizeof(int),ncapacity) << endl;
return 0;
}
「01揹包」最優方案總數分析及實現
本文為網上覆制 本人博文 揹包問題 01揹包 詳解及實現 包含揹包中具體物品的求解 中已談過01揹包,這裡再重寫一下01揹包的動態規劃狀態及狀態方程 設揹包容量為v,一共n件物品,每件物品體積為c i 每件物品的價值為w i 1 子問題定義 f i j 表示前i件物品中選取若干件物品放入剩餘空間為j...
揹包問題之最優方案總數
此處的最優方案是指物品總價值最大的方案。這裡以0 1揹包問題為例。給定資料如下 c 2 3,4 5,6 7,8 v 3,4,5,6,7,8,9 v 23 結合求最大總價值和方案總數兩個問題的思路,最優方案的總數可採取如下方式求解 令 dp i j dp i j dp i j 表示前i件物品在代價為j...
揹包問題 01揹包
有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...