揹包問題總結

2021-10-24 05:33:13 字數 1694 閱讀 1369

本篇記錄各種揹包問題及解決思路:

問題:有n件物品和乙個容量為v的揹包。第i件物品的價值是c[i],體積是v[i]。求解將哪些物品裝入揹包可使價值總和最大。總所周知,該問題使用動態規劃來求解,且狀態轉移方程為:

下面用具體例子來解釋:當 n = 4,v = 8 時,價值陣列為 c = ,v = 。對於本題我們要求的答案就是 dp[4][8] 的值,根據狀態轉移方程可以得到:

dp[i][j]代表當揹包容量為j處理(分為裝或者不裝兩種)第i件物品時可以達到的最大價值,j比物品i的體積小時說明放不下了,那麼就不裝,此時dp[i][j] = dp[i-1][j],代表容量為j處理物品i的最大價值與處理物品i-1時的最大價值相同。若可以放的下,我們需要考慮裝進去價值大還是不裝價值大,那麼為什麼裝進去的價值是 dp[i-1][j-v[i]] + c[i] 呢?因為只有剛剛好裝進去(裝滿揹包)才能達到理論上的最大價值,那麼 dp[i-1][j-v[i]] 就代表當容量正好剩餘物品i的體積且處理上乙個物品時的最大值,再加上物品i的價值則為裝入可得的最大值,兩者取大即可得到 dp[i][j]。

//0-1揹包問題(二維陣列)

//n代表物品數量,v代表揹包體積,product[0]為物品價值陣列,product[1]為物品體積陣列

private static int packageproblem(int n, int v, int product) }}

return result[n][v];

}

優化:如果手動實現過dp陣列就可以發現,求d[i][j]只與上一行(d[i-1]行)的資料有關,那麼我們可以將二維dp陣列用一維來實現,由於每次使用的是上一行靠前的元素([j-v[i]]),可以採用倒序迴圈來更新陣列,就可以實現利用前面的資料後再修改。

//0-1揹包問題(一維陣列)

private static int packageproblem1(int n, int v, int product)

}return result[v];

}

初始化的細節問題(引自揹包九講)我們看到的求最優解的揹包問題題目中,事實上有兩種不太相同的問法。有的題目要求「恰好裝滿揹包」時的最優解,有的題目則並沒有要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]為0其它f[1..v]均設為-∞,這樣就可以保證最終得到的f[n]是一種恰好裝滿揹包的最優解。如果並沒有要求必須把揹包裝滿,而是只希望**盡量大,初始化時應該將f[0..v]全部設為0。

為什麼呢?可以這樣理解:初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包可能被價值為0的nothing「恰好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果揹包並非必須被裝滿,那麼任何容量的揹包都有乙個合法解「什麼都不裝」,這個解的價值為0,所以初始時狀態的值也就全部為0了。

這個小技巧完全可以推廣到其它型別的揹包問題,後面也就不再對進行狀態轉移之前的初始化進行講解。練習

在0-1揹包的基礎上令這n件物品的數量為無窮大,則問題化為完全揹包問題,即每一件物品可以取任意多個,不是只有裝或不裝兩種狀態。

揹包問題 01揹包總結

寫這篇部落格的原因是因為自己初學揹包的時候覺得好玄學。只是知道怎麼寫,但是具體是為什麼覺得很玄妙。在此其實希望和我一樣的小白萌新早點明白其中的原理,其實原理很簡單,只要懂了這個圖,我想01揹包就不成問題了。首先要明確這張表是至底向上,從左到右生成的。關於01揹包的題目暫時整理了一點。1.簡單01揹包...

揹包問題總結

標籤 acm dp 揹包 n 物品,乙個揹包,每個物品價值wi 體積vi 揹包容量 c 求最大價值 對於物品 i可選可不選 fi j fi 1 j vi j 0 fi j max c j vi 給定 n 種物品和乙個揹包。第 i種物品的價值是 wi 其體積為vi 揹包的容量為 c 同一種物品的數量無...

揹包問題總結

揹包問題主要是分為三種 0 1揹包,完全揹包,多重揹包 1 0 1揹包 定義 何謂0 1揹包,可以這樣想,那裡有一堆值錢的東西,每一樣東西只有一件,他們的價值和體積都不一樣,現在要你從這n件裡面挑選一些放到乙個容量一定的揹包裡面,使得你的揹包裡的東西總價值最大。對於這些東西的每一件,你可以選擇放進你...