揹包問題(0 1揹包 完全揹包)

2022-05-21 16:00:13 字數 4812 閱讀 8080

0-1揹包

有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
重要的點在於:每種物品僅有一件,可以選擇放/不放子問題:f[i][v]表示前i件物品恰好放入乙個 容量為v 的揹包可以獲得的最大價值。

狀態轉移方程(遞推式):f[i][v]=max;//考慮前i件物品放入這個子問題的時候,可以轉化為前i-1件物品已經放好。那麼如果放入第i件物品,那麼問題轉化為 前i-1件物品放入剩餘容量為v-c[i]的揹包裡;如果不放入第i件物品,那麼問題轉化為 前i-1件物品放入剩餘容量為v的揹包裡。

而如果放入第i件物品,那麼當前價值就是f[i-1][v-c[i]]+w[i]。因此當前最大價值就是 放入&不放入 之間的最大值。

可以反向找到各種物品的選擇:從dp[n][v]開始,如果dp[i][j]=dp[i-1][j],則當前第i件物品沒有被選中,從dp[i-1][j]繼續找;否則,則表示選中,從dp[i-1][j-w[i]]開始找

偽**:

int dp=new

int[n][v+1

];//

初始化第一行

//僅考慮容量為v的揹包放第0個物品,不放物品,價值為0

for(int i=0;i<=v;i++)

//初始化第一列

//容量為0的揹包放物品,不放物品,價值為0

for(int i=0;i<=n;i++)

//根據狀態轉移方程,填充其他行和列

for(int i=1;i)

//容量足夠,可以放進去,比價值更大的方法

else

}}//

最後的結果

dp[n-1][v]

如何優化呢?那麼只能在空間複雜度上進行優化,只使用一維陣列來存放結果

此時狀態轉移方程為:f[v]=max;//那麼這個時候需要注意的是,在第二層迴圈中,需要使用從後往前計算,得到結果。即要用一維陣列記憶化的時候,需要用到當前位置的值 和 該位置之前的值。因為如果我們需要計算f[4, 4]=max、f[4,3]=max、f[4,2]=max。

如果是轉化為一維陣列,因為需要保證max中的f[v]是f[i-1][v],前面的f[v]是f[i][v]。也就是當前這一層的d[j]還沒有被更新過,所以當前的d[j]用到的是i-1層的結果。如果從前往後計算,那麼下一次使用的d[j]是本層已經更新過的,會覆蓋掉i-1層的結果。

//解釋

對於dp[j]=max而言,dp[j-w[i]]相當於二維的dp[i-1][j-w[i]],dp[j]是由前面的dp(1...j)推出來的。

因此比如從i=3推i=4,此時一維陣列存放,這是i=3時所有子問題的解。如果從前往後推,那麼計算i=4時,

dp[0]=0, dp[1]=0, ... , (前面這幾項都放不進 w[i]=5的物品)dp[5]=max=7, dp[6]=max=7, dp[7]=max=9.....這裡會更新dp[5]、dp[6]...的值,那麼後續計算的時候 就沒辦法用到 上一輪迴圈時的 dp[5]、dp[6]....了(即 因為當前值 是由上一輪迴圈推出來的,如果從前往後,前一次迴圈儲存下來的值 可能會被修改)就是我當前更新要用到這個值,但是這個值 在從前往後更新時,已經被修改了,那麼我用到的就是錯誤的值了。

初始化的話:(初始化 實際上是 在沒有任何物品可以放入揹包時 的合法狀態)

如果問法是「恰好裝滿」的最優解,那麼除了dp[0]初始化為0,其他都應該設定為 負無窮大。這樣能保證最終的dp[v]為恰好裝滿揹包時的最優解。此時,只有容量為0的揹包 可以在 什麼都不裝且價值為0時被「恰好裝滿」,因為如dp[3]則表示,揹包容量為3時,恰好裝滿的價值,此時沒有合法的解,因此屬於未定義狀態,設為無窮大。

如果問法是「可以不裝滿」的最優解,那麼所有的都應初始化為0,因為「什麼都不裝」時,0就是合法解。

偽**:

int dp=new

int[v+1

];//

初始化第一行

//僅考慮容量為v的揹包放第0個物品,不放物品,價值為0

for(int i=0;i<=v;i++)

//根據狀態轉移方程,填充其他行和列

for(int i=1;i)}//

最後的結果

dp[v]

例題:給定乙個僅包含正整數的非空陣列,確定該陣列是否可以分成兩部分,要求兩部分的和相等

思路:即給定n個元素組成的陣列arr,陣列元素的和為sum。轉換成揹包問題,每個物品的重量和價值為arr[i],兩部分和相等,即揹包的限重為sum/2.

if(nums==null || nums.length==0

)int sum=0

;for(int

num : nums)

//如果sum不可以平分,那麼就不可分為兩塊

if(sum%2!=0

)sum/=2;//

定義boolean dp=new boolean[sum+1

];//

初始化dp[0]=true

;for(int i=1; i)}//

輸出dp[sum]

例題擴充套件:傳入陣列的大小+乙個int型陣列,返回該陣列能否分成兩組, 使得兩組中各元素加起來的和相等。

並且,所有5的倍數必須在其中乙個組中,所有3的倍數在另乙個組中(不包括5的倍數),能滿足以上條件,返回true;不滿足時返回false。

public

static

void

main(string args)

else

if (num%3==0

)

else

}//如果剛好都是3和5的倍數,那麼不需要進行接下來的步驟

if (othernums.size()==0

)

else

}//接下來問題轉化為,將剩餘不是3和5的倍數的數,均分到兩個組裡。使得

//3的倍陣列之和+組a=5的倍陣列之和+組b -->(3的倍陣列之和-5的倍陣列之和)+組a=組b-->可以把兩組之差當成乙個值

else

//如果不能均分,那麼返回false

if (sumtemp%2!=0

)

else

if (candivided(othernums, othernums.size(), sumtemp/2

))

else}}

}//是否可以將鍊錶中的數分為兩組,每組的和為總和的1/2。

//這裡用的是二進位制列舉,二進位制的每乙個01位可以當成這個數字加不加進去

private

static boolean candivided(listothernums, int size, int

sum)

else

}if (cursum ==sum)

}return

false

; }

//上乙個函式還可以用01揹包的方法來做。

private static boolean candivided(listothernums, int size, int sum)

}return dp[sum];

}

完全揹包

有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
重要的區別在於完全揹包是 每種無限件

狀態轉移方程:f[i][j]=math.max(f[i-1][j-k*c[i]]+k*w[i]),0<=k*c[i]<=j;//根據第i件物品放多少件,即前i-1件物品中 選擇 若干件 放入剩餘的空間上,使得最大。(f[i][j]表示 前i種物品 放入乙個容量為j的揹包種獲得 最大價值)

//遞迴和動態規劃的區別:動態規劃多使用了乙個二維陣列來儲存中間的解

**:

int dp=new

int[n][v+1

];//

初始化第一行

//僅考慮容量為v的揹包放第0個物品,不放物品,價值為0

for(int i=0;i<=v;i++)

//初始化第一列

//容量為0的揹包放物品,不放物品,價值為0

for(int i=0;i<=n;i++)

//根據狀態轉移方程,填充其他行和列

for(int i=1;i)

//容量足夠,可以放進去,比價值更大的方法。取k個物品i,再k種選擇 選出 最優解

else

}

}}//

最後的結果

dp[n-1][v]

同樣使用一維陣列 來優化 空間複雜度

dp[i]=math.max(dp[i], dp[i-w[i]]+v[i])

int dp=new

int[v+1

];//

初始化第一行

//僅考慮容量為v的揹包放第0個物品,不放物品,價值為0

for(int i=0;i<=v;i++)

//根據狀態轉移方程,填充其他行和列

for(int i=1;i)}//

最後的結果

dp[v]

(示意圖源於網路,侵刪)

揹包問題 01揹包 完全揹包 多重揹包

01揹包和完全揹包的區別 01揹包的侷限在於每樣物品只有一種,每個物品都有乙個屬於自己的價值和重量,在給定的物品中選出揹包所能容納的最大重量,要求是價值最大 完全揹包與01揹包的不同在於完全揹包不限制每樣物品的個數,物品的價值和質量都與01揹包一樣,也同樣是求在給定大小的容量中,找出最大價值的選擇 ...

揹包問題(01揹包,完全揹包,多重揹包)

揹包問題 01揹包,完全揹包,多重揹包 近日為以下瑣事煩身 差不多要向學院提交專案申請了,本來是想做個多模式的im系統的,可是跟往屆通過審核的專案比起來,缺乏創新和研究價值,所以在文件上要多做手腳,花點心思。揹包問題,經典有揹包九講。不死族的巫妖王發工資拉,死亡騎士拿到一張n元的鈔票 記住,只有一張...

揹包問題 01揹包,完全揹包,多重揹包

有goods num件物品,max volume的最大裝載量,每種物品只有一件,每種物品都有對應的重量或者說體積volume i 價值value i 求解裝包的最大價值 假設目前已經有 i 1件物品裝在容量為 j 的揹包中,並且得到最大價值package i 1 j 當前裝第i件,那麼討論分兩個角度...