在昨天我已經很詳細的講解過01揹包的動態規劃問題了,今天我講解的是徹底揹包的問題,這是01揹包的詳解:http://www.cnblogs.com/Kalix/p/7617856.htmlhtml
先看問題:在n種物品中選取若干件(同一種物品可屢次選取)放在空間爲v的揹包裏,每種物品的體積爲c1,c2,…,cn,與之相對應的價值爲w1,w2,…,wn.求解怎麼裝物品可以使揹包裏物品總價值最大算法
看完這個問題,你也許會以爲這個不就是01揹包的升級版嗎,其實就是這樣,徹底揹包問題與01揹包問題的區別在於徹底揹包每一件物品的數量都有無限個,而01揹包每件物品數量只有1個數組
因此說與它相關的策略已經不是隻有取和不取這兩種策略了,而是有取0件、取1件、取2件……等等不少種策略優化
若是咱們用和01揹包同樣的狀態,f[i][v]表示前i種物品恰放入一個容量爲v的揹包的最大價值,那咱們應該用k表示當前容量下能夠裝第i種物品的件數,那麼k的範圍應該是0≤k≤v/c[i],
spa
既然要用當前物品i把當前容量裝滿,那須要0≤k≤v/c[i]件,其中k表示件數。htm
下面給出狀態轉移方程:blog
f[i][j] = max{f[i-1][j],f[i-1][j - k * c[i]] + k * w[i]}(0<=k*c[i]<=v)排序
貼一段代碼:繼承
for (int i = 1; i < n; i++){ for (int j = 1; j <= v; j++){ for (int k = 0; k*c[i] <= j; k++){ if(c[i]<=j)/*若是能放下*/ f[i][j] = max{f[i][j],f[i-1][j - k * c[i]] + k * w[i]};/*表示前i-1種物品中選取若干件物品放入剩餘空間爲j-k*w[i]的揹包中所能獲得的最大價值加上k件第i種物品的總價值*/ else/*放不下的話*/ f[i][j]=f[i-1][j]/*繼承前i-1個物品在當前空間大小時的價值*/ } } }
咱們能夠對其進行優化:若是有兩件物品a、b知足c[a]<=c[b]且w[a]>=w[b],則將物品b去掉,不用考慮。由於你能夠用 佔用體積小的物品 獲得 比 佔用體積大的物品還要多的價值,何樂而不爲呢。其實對於徹底揹包,能夠再優化,首先將容量大於v的物品去掉,而後排序計算出容量相同的物品中價值最高的是哪一個,咱們只要價值大的就能夠了。ci
畫一個v=6,c[1]=1 , w[1]=3 ; c[2]=3 , w[2]=10的表格
i\j |
j=0 | j=1 | j=2 | j=3 | j=4 | j=5 | j=6 | ||
i=0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
i=1 |
0 | 3 | 6 | 9 | 12 | 15 | 18 | ||
i=2 |
0 | 3 | 6 | 10 | 13 | 16 | 20 |
以上算法能夠理解成:dp每一種物品在不一樣剩餘容量下的最優解,他是以每1種作單位的,每一種物品能夠包含若干個該物品。考慮是否在該種物品中添加一件新的該物品
咱們再進行優化,改變一下dp思路
咱們能夠把把徹底揹包問題轉化爲01揹包問題來解,第i種物品最多選V/c[i]件,因而能夠把第i種物品轉化爲v/c[i]件費用及價值均不變的物品,而後求解這個01揹包問題。
即:將一種物品拆成多件物品。
咱們如今dp每個物品,dp出該種物品在不一樣剩餘容量下的最優解,他是以每1個爲單位的。考慮是否在當前全部物品總數中添加一件新的該物品
咱們用i表明前i種物品,v表明包的最大承重,c[i]是第i種物品消耗的空間、w[i]是第i種物品的價值、f[i,j]是最大價值(從前i種物品取若干件放入有j個剩餘空間的包)。
若是不放那麼f[i][j]=f[i-1][j]
若是肯定放,那麼f[i][j]=f[i][j-c[i]+w[i]],爲何會是f[i][j-c[i]]+w[i]?
由於咱們要考慮的是在當前基礎上添加一件物品i。
就是說若是你放第i種物品,並不牽扯到第i-1種物品,因此無論你放多少件,都要在第i種商品的基礎上操做
因此說遞推式爲:
f[i][j]=max(f[i-1][j],f[i][j-c[i]]+w[i])
該代碼:
for (int i = 1; i <= n; ++i) { for (int j = 1; j <= v; ++j) { if (c[i] <= j) f[i][j] = max(f[i - 1][j],f[i][j - c[i]] + v[i]); else f[i][j] = f[i - 1][j]; } }
咱們能夠繼續優化此算法,能夠用一維數組寫
咱們先回顧01揹包爲何寫1維要逆序?
由於爲了不要使用的子狀態收到影響。
那咱們該如何寫徹底揹包的1維優化呢?
答案是:順序
由於第i種物品一旦出現,原來沒有第i種物品的狀況下可能有一個最優解,如今第i種物品 出現了,而它的加入有可能獲得更優解,因此以前的狀態須要進行改變,故須要正序。
因此說遞推式是這樣子的:
f[j] = max(f[j],f[j-c[i]]+w[i])
貼出代碼:
for (int i = 1; i <= n; ++i) { for (int j = w[i]; j <= v; ++j) { f[j] = max(f[j], f[j - c[i]] + v[i]); } }
若是此文寫的有bug,請及時留言!謝謝
本文章原創
Authentic Author : Tranx
2017.10.2 19:18