標籤: 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 ,同一種物品的數量無限多。可以任意選擇裝入揹包中的物品,求裝入揹包中物品的最大總價值。
fi[j] = fi-1[j] (vi>j>=0)
fi[j] = max (c>=j>=vi) //注意第二個是 fi 而不是
fi-1,與 0-1 揹包區別僅在於此,因為允許在放過的基礎上再增加一件。
給定 n 種物品和乙個揹包。第 i 種物品 的價值是 wi ,其體積為 vi,數量是 ki件,揹包的容量為 c。可以任意選擇裝入揹包中的物品,求裝入揹包中物品的最大總價值。
首先對於第 i 種物品,不能確定放多少件才是最優的,因為並沒有什麼可以證明放一件或者全放一定會更優。換句話說,最優解所需要的件數,可能是 0 到 ki 中的任何數。
不需要把一種物品拆分成 ki
份,而是只要物品拆分到能湊出 1 到 ki
之間任意數量的程度就可以了。
可以證明,按照二進位制的拆分能使件數達到最小,把 ki
拆分成1,2,4…2t,ki
-2^(t+1)+1(2^(t+2)>ki
>=2^(t+1)),就一定可以滿足最優解要求了。下一步,還是用 0-1 揹包的經典演算法。
如此,我們得到了乙個時間複雜度為 o(c*∑([log2ki]))的演算法。
多重揹包參考引用原址
網上關於「多重揹包」的資料倒是不少,但是關於怎麼實現o(n*v)演算法的資料,真得好少呀,關於「單調佇列」那部分演算法,又沒說明得很清楚,看了幾遍沒看懂原理,只好自己動腦去想怎麼實現o(n*v)演算法。
若用f[i][j]表示對容量為j的揹包,處理完前i種物品後,揹包內物品可達到的最大總價值,並記m[i] = min(n[i], j / v[i])。放入揹包的第i種物品的數目可以是:0、1、2……,可得:
f[i][j] = max (0 <= k <= m[i]) ㈠
如何在o(1)時間內求出f[i][j]呢?
先看乙個例子:取m[i] = 2, v[i] = v, w[i] = w, v > 9 * v,
並假設 f(j) = f[i - 1][j],觀察公式右邊要求最大值的幾項:
j = 6*v: f(6*v)、f(5*v)+w、f(4*v)+2*w 這三個中的最大值
j = 5*v: f(5*v)、f(4*v)+w、f(3*v)+2*w 這三個中的最大值
j = 4*v: f(4*v)、f(3*v)+w、f(2*v)+2*w 這三個中的最大值
顯然,公式㈠右邊求最大值的幾項隨j值改變而改變,但如果將j = 6*v時,每項減去6*w,j=5*v時,每項減去5*w,j=4*v時,每項減去4*w,就得到:
j = 6*v: f(6*v)-6*w、f(5*v)-5*w、f(4*v)-4*w 這三個中的最大值
j = 5*v: f(5*v)-5*w、f(4*v)-4*w、f(3*v)-3*w 這三個中的最大值
j = 4*v: f(4*v)-4*w、f(3*v)-3*w、f(2*v)-2*w 這三個中的最大值
很明顯,要求最大值的那些項,有很多重複。
根據這個思路,可以對原來的公式進行如下調整:
假設d = v[i],a = j / d,b = j % d,即 j = a * d + b,代入公式㈠,並用k替換a - k得:
f[i][j] = max + a * w[i] (a – m[i] <= k <= a) ㈡
對f[i - 1][y] (y= b b+d b+2d b+3d b+4d b+5d b+6d … j)
f[i][j]就是求j的前面m[i] + 1個數對應的f[i - 1] [b + k * d] - k * w[i]的最大值,加上a * w[i],如果將f[i][j]前面所有的f[i - 1][b + k * d] – k * w放入到乙個佇列,那麼,f[i][j]就是求這個佇列最大長度為m[i] + 1時,佇列中元素的最大值,加上a * w[i]。因而原問題可以轉化為:o(1)時間內求乙個佇列的最大值。
該問題可以這樣解決:
① 用另乙個佇列b記錄指定佇列的最大值(或者記錄最大值的位址),並通過下面兩個操作保證佇列b的第乙個元素(或其所指向的元素)一定是指定佇列的當前最大值。
② 當指定佇列有元素m進入時,刪除佇列b中的比m小的(或佇列b中所指向的元素小等於m的)所有元素,並將元素m(或其位址)存入佇列b。
③ 當指定佇列有元素m離開時,佇列b中的第乙個元素若與m相等(或佇列b第乙個元素的位址與m相等),則佇列b的第乙個元素也離隊。
經過上述處理,可以保證佇列b中的第乙個元素(或其指向的元素)一定是所指定佇列所有元素的最大值。顯然佇列b的元素(或其所指向的元素)是單調遞減的,這應該就是《揹包九講》中的提到的「單調佇列」吧,初看的時候被這個概念弄得稀里糊塗,網上的資料提到「維護佇列的最大值」,剛開始還以為是維護這個單調佇列的最大值,對其採用的演算法,越看越糊塗。其實,只要明白用乙個「輔助佇列」,求另乙個佇列的最值,那麼具體的演算法,和該「輔助佇列」的性質(單調製化),都很容易推導出來。
在多重揹包問題中,所有要進入佇列的元素個數的上限值是已知的,可以直接用乙個大陣列模擬佇列。
好題推薦:
poj 1742
:= 經典題解
揹包問題 01揹包總結
寫這篇部落格的原因是因為自己初學揹包的時候覺得好玄學。只是知道怎麼寫,但是具體是為什麼覺得很玄妙。在此其實希望和我一樣的小白萌新早點明白其中的原理,其實原理很簡單,只要懂了這個圖,我想01揹包就不成問題了。首先要明確這張表是至底向上,從左到右生成的。關於01揹包的題目暫時整理了一點。1.簡單01揹包...
揹包問題總結
揹包問題主要是分為三種 0 1揹包,完全揹包,多重揹包 1 0 1揹包 定義 何謂0 1揹包,可以這樣想,那裡有一堆值錢的東西,每一樣東西只有一件,他們的價值和體積都不一樣,現在要你從這n件裡面挑選一些放到乙個容量一定的揹包裡面,使得你的揹包裡的東西總價值最大。對於這些東西的每一件,你可以選擇放進你...
揹包問題總結
n件物品,v容量,每件物品的代價v i 價值w i 01揹包 每種物品只能取乙個,for i 1 to n for j v to v i f j f j v i w i 完全揹包 每種物品可以取無限個,但是體積不能超過v,for i 1 to n for j v i to v f j f j v i...