揹包問題九講筆記 01揹包問題

2021-08-08 06:07:01 字數 2754 閱讀 4732

n 件物品和乙個容量為

v的揹包.放入第

i 件物品.放入第

i件物品耗費的容量是ci

,所獲得的價值是wi

.每件物品只有乙個.求將哪些物品放入揹包可使價值總和最大.

一般來說求極值的問題可分為貪心,動態規劃,以及遍歷所有可能.在這三中方法中,動態規劃是最常見的,也是很難想出來的.其中最難的是定義子問題,寫出動態轉移方程.類似於將問題簡化,如何由較小的子問題,推到出較複雜的問題.類似的計算機的本質是極其簡單的二進位制運算,但由無數二進位制運算疊加在一起,組成了今天覆雜的網際網路系統.

在上次面試中,由於沒想出思路,很緊張,之後寫最簡單的01揹包也沒有寫出來.面試後,痛定思痛,之後要逐步加強的自己的演算法思維能力,證明問題能力,找錯能力,工具應用能力.

一般可從最簡單入手:用f

[i,v

] 表示前

i 件物品放入乙個容量為

v的揹包所獲得的最大價值.

在放與不放兩個子問題中選擇乙個最大的解 f[

i,v]

=max

(f[i

−1,v

],f[

i−1,

v−ci

]+wi

)

f[0, 0...v] = 0

for i = 1 to n

for j = 0 to v

if(c[i] > j)

f[i, j] = f[i - 1, j]

else

f[i, j] = max(f[i - 1, j], f[i - 1, j - c[i]] + w[i])

時間複雜度已無法再優化,. t=

o(nv

) 這裡使用的是二維資料,但求解第

i 行值時,只利用到i−

1行的解,並未利用更久之前的解,由於有這種侷限解的特性,可以利用一維的滾動陣列模擬二維資料,另外由於這裡由i−

1 的前面的解j−

c[i]

推導出i 後面的解

j,也就是利用一維的資料的話,舊解為前面的解,新解為後面的.那麼就應該讓

j 從大到小進行迴圈遍歷,因為這樣第一次接觸的到為舊解i−

1,新出來的新解

j 在此次遍歷也不會再用到.也就是當且僅使用了一次.如果是從小到大遍歷

j,那麼新求出的解j+

c[i]

在後面還會遍歷到,因此還會被重新用到,再次用到的話,還會選擇是否拿下這個物體,不符合題意每件物品只有乙個(如果有無窮多個物品,就可以從小到大遍歷,之後的完全揹包問題會提到)s=

o(v)

f[0...v] = 0

for i = 1 to n

for j = v to c[i]

f[j] = max(f[j], f[j - c[i]] + w[i]

**更將簡單優雅

如果是求恰好要裝滿揹包時的最優解,那麼像上面的都初始化為0就不行了.這時候需要只有f[0, 0] = 0, f[0, 1…v] = int_min(表示負無窮).可以理解只有0個物品,揹包為0容量正好有解,其餘解為無效解.如果手工畫出來子問題轉化圖示,這樣最基礎的子問題只能從f[

0,0]

出發,不會從其他無效子問題出發,因為初始化無效解是負無窮,兩者去較大的話,肯定不會選取負無窮.

可將偽**1再次優化為

for i = 1

to n

for j = v to

max(v - sum(c[i...n]), c[i])

f[j] = max(f[j], f[j - c[i]] + w[i])

由於只需要最後f[v]的值,倒推前乙個物品,其實只要知道f[v-c[n]]即可。以此類推,對以第j個揹包,其實只需要知道到f[v-sum]即可

參照一般動態規劃問題輸出方案的方法:記錄下每個狀態的最優質是由狀態轉移方程的哪一項得到的,也就是記錄最優解時,是否選擇了這個物品.具體來說是利用path[i, j] 來記錄當前的轉移過程,path[i, j] = true表示選取物品i, path = false 表示未選取當前物品.(bool陣列更加節省記憶體).空間複雜度s=

o(vn

) .

void zeroonepack(int c, int w, int v, vector

& f)

int allzeroonepack(vector

& c, vector

& w, int v)

void zeroonepack(int i, int c, int w, int v, vector

& f, vector

> &path)

}}int allzeroonepackdetail(vector

& c, vector

& w, int v)

return f[v];

}void printmethod(vector

& c)

i--;

}}

在利用dfs遞迴求解時,先將物品按照單位**排好序,單位**高的靠前,這樣如果某個物品超載時,沒必要再累積其後面物品的**, 而是按照該物品的單位**乘以剩餘容量,這樣算出的總**雖然比實際裝載的總**略高些,如果這樣略高於實際值的解還低於當前的最優解,則可對後面剪枝,避免多餘的計算.

揹包九講

0-1揹包問題(回溯結點類排序改進)

01揹包問題:charm bracelet (poj 3624)(外加乙個常數的優化)

揹包九講 01揹包問題

1 01揹包問題描述 已知 有 n 件物品和乙個容量為 v 的揹包。第i件物品的重量為w i 得到的價值是 c i 問題 求解將哪些物品裝入揹包可使價值總和最大。條件 每種物品只有一件,可以選擇放或者不放 2 基本思路 01揹包的特點 每種物品只有一件,可以選擇放或者不放 子問題定義狀態f i v ...

揹包問題模板(揹包九講)

題目 有 n 件物品和乙個容量為 v 的揹包。第 i 件物品的體積 費用 是 c i 價值是 w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。如下 一維陣列 include include include using namespace std define m ...

揹包九講 01揹包問題(dp 滾動陣列)

現在有n件物品和乙個容量為v的揹包。第i件物品的費用是cost i 價值是value i 每個物品最多只能選一次,求解在不超過揹包容量的限制下,如何選取物品組合能使收益最大化?題型有兩種,一種要求揹包恰好放滿,一種不要求揹包恰好放滿 現在考慮第二種題型,即不要求揹包恰好放滿 將問題分解成子問題 有i...