有n件物品和乙個容量為v的揹包。放入第i件物品耗費的空間是ci,得到的價值是wi。求解將哪些物品裝入揹包可使價值總和最大。
f[i,v]表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。則其狀態轉移方程便是:f[i,v]=max
然後根據這個方程便可以寫出偽**,具體**最好根據不同題目具體要求來寫,過度依賴原始碼很容易犯錯。
f[0, 0...v] <- 0
for i <- 1 to n
for v <- ci to v
f[i, v] <- max(f[i-1, v], f[i-1, v-ci] + wi)
其實可以省去狀態裡面的一維。具體原理如下:f[i, v]是由f[i-1, v]和f[i-1, v-ci]兩個子問題遞推而來,所以只需在主迴圈中以 v <- v...ci的方式來遞推的話,就能夠保證使用的是上一組的f[v],f[i-1]。具體偽**如下:
f[0...v] <- 0
for i <- 1 to n
for v <- v to ci
f[v] <- max(f[v], f[v-ci] + wi)
求最優解的揹包型別題目中,有兩種類似的問法。一種是問「
恰好裝滿揹包」的最優解,有的只要求「
不超過揹包容量即可」。
如果是要求恰好裝滿的問法時候,那麼在初始化時候只有f[0]被初始化為0,其他的狀態都應該為未定義狀態-inf。如果
是後者的問法時,應該將f[0...v]全部初始化成0。可以這樣理解:初始化的f陣列實際上就是什麼都不放的情況下的合法狀態,在第一種問法下很明顯只有f[0]才滿足什麼都不裝的情況下被「裝滿」,而後者的問法沒有要求必須把揹包裝滿,所以什麼都不裝也是合法的!
可以將這個初始化技巧推廣到其它型別的揹包問題!
有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。放入第i種物品的耗費的空間是ci,得到的價值是wi。求解:將哪些物品裝入揹包,可使這些物品的耗費的空間總和不超過揹包容量,且價值總和最大。
一種最容易想到的思路就是用01揹包的思路來求解,狀態定義與01揹包一樣。方程為:f[i,v]=max。k表示第i中物品選多少個。可以將偽**描述如下。
f[0, 0...v] <- 0
for i <- 1 to n
for v <- ci to v
for k <- 0 to v/ci
f[i, v] <- max(f[i-1, v], f[i-1, v-k*ci] + k*wi)
但是這個演算法複雜度有點高,複雜度大概為o(vn * sum(v/ci))。用於題目中很可能超時,所以要給出優化。
首先給出偽**:
f[0...v] <- 0
for i <- 1 to n
for j <- ci to v
f[j] <- max(f[j], f[j - ci] + wi)
和01揹包的滾動陣列方法很像,只有迴圈順序不一樣。
對於以上的這份偽**,可以這樣理解:01揹包之所以選擇逆序來遍歷第二重迴圈,是為了
保證在求f[j]時,用的是上一次所更新的f值。換個思路,也就是說是為了讓每個物品能夠恰好被選入一次!如果不是逆序來遍歷的話,很可能將已經選入的物品再次選入。
所以模擬一下完全揹包,完全揹包需要的正是可以將已經選入的物品再次選入的性質,所以採取了這種寫法!
有n種物品和乙個容量為v的揹包。第i種物品最多有mi件可以用,每件耗費的空間是ci,價值是wi。求解將哪些物品裝入揹包可使這些物品的耗費的空間總和不超過揹包容量,且價值總和最大。
最基本的思路還是轉換成01揹包問題來求解。具體狀態和轉移方程和完全揹包大同小異。具體的偽**也和完全揹包一樣,只不過將v/ci代替成mi而已,不再贅述。
在完全揹包裡面已經說明了這種最樸素的演算法複雜的比較高,所以還是依照
如果有c[i]*m[i]>=v,則可以使用完全揹包的求法來對這一種物品求解!這個思路的正確性也是顯而易見的。如果這類物品的所有耗費大於或者等於容量限制,則不論怎麼選也不會超過這類物品的數量c[i],所以相當於數量是無限的!偽**如下:
f[0...v] <- 0
for i <- 1 to n
if(c[i] * m[i] >= v)
else
for j <- v to m[i] * c[i] //注意最後還有一次
f[j] = max(f[j], f[j - m[i] * c[i]] + m[i] * w[i])
}
若問題只是問是否能夠裝滿容量為j的揹包,則有乙個複雜度為o(vn)的解法。設dp[i][j]為用前i種物品填滿容量為j的揹包後,最多還剩下多少種i類物品。根據狀態不難定義出轉移方程。若dp[i-1][j]>=0,說明用前i-1種物品就可以填滿j容量的物品,i物品可以乙個不用,所有此時dp[i][j] = m[i]。若j < c[i],或者dp[i - 1][j - c[i]] < 0,說明用前i-1種物品無法湊成容量j-c[i]的揹包,則再加上第i種揹包任然無法湊成容量為j的揹包,所以此時d[i][j] = -1。若是前i-1種能夠湊出容量j - c[i]的揹包,則再加上1個i類物品就可以湊成容量j的揹包,有dp[i][j] = dp[i-1][j-c[i]] - 1。偽**描述如下(為了節省空間,使用了滾動陣列):
dp[0...v] = -1
dp[0] = 0;
for i <- 1 to n
for j <- 1 to v
if(dp[j] >= 0) dp[j] = m[i]
else if(j < c[i] || dp[j - c[i]] <= 0) dp[j] = -1
else dp[j] = max(dp[j], dp[j - c[i]] - 1)
if(dp[v] >= 0) return true
else return false
揹包問題大總結 揹包九講
0 1揹包問題 其中w代表i個物品的重量,v代表其價值 其中n個物品 其中m是揹包的容量 result max f n 0 m 有 n 件物品和乙個容量是 v 的揹包。每件物品只能使用一次。第 i 件物品的體積是 wi,價值是 vi。求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價...
揹包九講 簡單揹包
揹包問題是一種動態規劃演算法的衍生問題。它可以被看作一種獨立的題型,也可以看作是一種線性動態規劃。學好揹包 學會揹包,對於深入理解動態規劃演算法有著極大的好處,並能幫助理解一些更深層次的動態規劃問題。那麼就開始吧 題目型別 有 n 件物品和乙個容量為 v 的揹包。第 i 件物品的費體積是 v i 價...
揹包問題九講筆記 01揹包問題
有 n 件物品和乙個容量為 v的揹包 放入第 i 件物品 放入第 i件物品耗費的容量是ci 所獲得的價值是wi 每件物品只有乙個 求將哪些物品放入揹包可使價值總和最大 一般來說求極值的問題可分為貪心,動態規劃,以及遍歷所有可能 在這三中方法中,動態規劃是最常見的,也是很難想出來的 其中最難的是定義子...