揹包問題 「01揹包」最優方案總數分析及實現

2021-06-17 16:27:10 字數 3736 閱讀 7643

-----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 ...