1. 程式人生 > 其它 >關於揹包DP

關於揹包DP

今天在AKWING上學了點揹包基礎,簡單記錄一下:

首先,啥是揹包問題???

簡單舉個例子,現在你是一個小偷,有一個包用來裝你偷的東西,這個包的容量是有限的,假設你知道每件物品的價值和所佔體積,你現在要決定要裝走一些物品,使帶走的物品價值最高。

這就是所謂的01揹包問題,就是需要考慮權重的求最優解DP問題。

那這道題的思路是什麼呢?

其實跟一般的DP相似(在不考慮優化的基礎上),就是考慮當前狀態的取捨來進行狀態轉移,(對於任意一個物品,你有兩種選擇,要麼選(對應1),要麼不選(對應0)),從而得到問題的最優解

針對DP問題,套上一般思路進行求解:

首先設定變數,一個二維陣列 f[i][j] 代表只考慮 前 i 個物品,體積不超過 j 的狀態的最大值

(就是最大獲利)

再建兩個陣列,v[i]和w[i],分別表示第i個物品的體積和價值

那還有就是狀態計算,像原來一樣,我們還是把狀態分為兩部分來考慮,一是選取第 i 個物品是的最大值,因為不選第 i 個,所以也就是從前 i-1 個物品中選取唄,那就是說: f[i][j] = f[i-1][j]

第二種情況就是選第 i 個物品,那就是前面 i-1個物品的選擇最大值,加上第i個物品的最大值,也就是:f[i][j] = f[i-1][j-vi] + w[i]

還有就是初始化,f[0][i]=0,也就可以省略了

還可以改成一維陣列:(滾動陣列)

如果只用到了 i 和 i-1,那就可直接改成一維的

完全揹包問題:

與01揹包相似,區別就在於01揹包每件物品最多隻能選一次,而完全揹包問題中的每個物品都有無數件

狀態表示:依舊是所有隻考慮前 i 個物品,且總體積不大於 j 的所有選法

狀態計算:將其分為若干組,第i個物品選0個,選1個,選2個。。。選k個

選0個:f[i][j]=f[i][j-1]

其他的:1.去掉n個物品i

2求max,3.再加回來n個物品i的值。

即:f[i,j]=f[i-1,j-v[i]*n]+w[i]*n

f[i,j]=max(f[i-1,j],f[i-1,j-v[i]*1]+w[i]*1,f[i-1,j-v[i]*2]+w[i]*2,f[i-1,j-v[i]*3]+w[i]*3+......+f[i-1,j-v[i]*n]+w[i]*n)

f[i,j-v[i]]=max(f[i-1,j-v[i]*1]+w[i]*1,f[i-1,j-v[i]*2]+w[i]*2,f[i-1,j-v[i]*3]+w[i]*3+......+f[i-1,j-v[i]*n]+w[i]*n)

所以:f[i,j]=max(f[i-1,j] , f[i-1,j-v[i]]+w[i] ],直接少了一層列舉n的迴圈。

多重揹包問題:(有有限數量的件數)

狀態表示與原來一樣

狀態計算也與完全揹包差不多:(設s[i]為第i個物品的數量)

f[i,j]=max(f[i-1,j],f[i-1,j-v[i]*1]+w[i]*1,f[i-1,j-v[i]*2]+w[i]*2,f[i-1,j-v[i]*3]+w[i]*3+......+f[i-1,j-v[i]*s[i]]+w[i]*s[i])

f[i,j-v[i]]=max(f[i-1,j-v[i]*1]+w[i]*1,f[i-1,j-v[i]*2]+w[i]*2,f[i-1,j-v[i]*3]+w[i]*3+......+f[i-1,j-v[i]*(s[i]+1)]+w[i]*(s[i]+1))

多了一項s[i]+1,無法和完全揹包使用一樣的優化方法

轉換方法:二進位制轉換

比如說有1023個物品i

將其劃分為若干組:1,2,4,8,16,32,64,128,256,512

再比如有200個物品i

將其劃分成1,2,4,8,32,64,73

此時從0到s[i]之間任意的數都能用他們相加表示出來:

分組揹包問題:

有若干組,每組裡有若干件物品,要求每組最多選一個,使得價值最大且不超過揹包限制

狀態表示:只從前i組物品中選,且總體積不大於j的所有選法最大值