揹包,顧名思義,就是乙個揹包。(……),其實就是在乙個揹包中裝東西,運用各種高階操作,而裝出各種奇怪的東西的一種演算法。
看題目就知道,揹包一共被分為九種,各種揹包所對應的題目和解法也是非常奇怪的啊。
那麼種類如下:
①0/1揹包
②完全揹包
③多重揹包
④混合揹包
⑤二維費用的揹包
⑥分組的揹包
⑦依賴揹包
……等等(請原諒!(please excuse me!))
那麼我們今天就是說一說前四種,也就是0/1揹包、完全揹包、多重揹包以及混合揹包這四種。
那麼我們接下來分塊複習。
一、0/1揹包
可以說接下來的一切揹包問題中0/1揹包是基礎。
下面的絕大多數奇怪的以及奇怪的以及奇怪的揹包都是有0/1揹包轉換而來。
原諒我(excuse me!)!揹包真的沒有什麼概念可言,我們直接上例題。
問題描述:有n件物品和乙個容量為c的揹包。第i件物品的重量為w[i],價值為v[i].問將那些物品放入揹包可使獲得的價值最大。
分析:eng~~貪心?每次找最大值?呵呵~你想多了,乙個資料直接卡死。
例如:c為10.接下來的價值及其對應重量為:
價值:10 8 7
重量:10 5 5
例如這組資料,正解是取價值為8和7的物品。而貪心卻炸了
那麼我們接下來想正解:
思想:動態規劃
那麼我們就要相想出狀態轉移方程
我們開始想:一件物品,只有兩種狀態,一種是取,一種是不取,那麼我們就可以想出以下狀態轉移方程:
f[i][j]=max(f[i][j],f[i][j-w[i]]+v[i])
f[i][j]表示前i件物品恰放入揹包中的最大價值
那麼我們繼續想:如果將資料很大是呢??不是會mle嗎??我們就繼續優化。
我們通過觀察二維陣列的狀態轉移方程發現f[i][c]只與f[i-1]這一層有關係,所以,我們考慮將i這層維數給優化掉。進一步發現f[i][c]只與f[i-1][c]和f[i-1]和f[i-1][c-w[i]]有關,如果想把i這個維數省掉的話,第i層的f[c]只與第i-1層的f[c]和f[c-w[i]]有關,因為f[c-w[i]]在f[c]的左邊,所以我們在求f[c]的時候,必須保證f[c-w[i]]還是第i-1階段的最優值,在下面**的遞推時,c要從c開始,倒著推,只有這樣,才能保證f[c]左邊的狀態沒有被第i個物品更新過,還是i-1層的狀態。
**如下:
for (inti=1;i<=n;i++)
for (int c=c;c>=0;c--)
if (c>=w[i])f[c]=max(f[c],f[c-w[i]]+v[i]);
那麼這就是0/1揹包
二、完全揹包
問題描述:有n件物品和乙個容量為c的揹包。第i件物品的重量為w[i],價值為v[i].每件物品可以放無數次。問將那些物品放入揹包可使獲得的價值最大。
分析:既然我們之前說道0/1揹包倒的迴圈是為了避免更新重複的狀態。那我們是否再從反面取想:我們是否可以將剛剛的0/1揹包的倒得迴圈轉換成正的迴圈呢??
事實上就是這樣
那麼**如下:
for (inti=1;i<=n;i++)
for (int c=0;c<=c;c++)
if (c>=w[i])f[c]=max(f[c],f[c-w[i]]+v[i]);
絕望吧~吧~吧~
三、多重揹包
問題描述:將n間物品和乙個容量為c的揹包。第i種物品的重量是w[i],價值為v[i],數(shù)量(liàng)為
a[i]
。 求最大的價值。
分析:二進位制法:按照二進位制法分割物品。比方說,物品i有13個,就可以把它分成係數為1、2、4、6共四個0/1揹包的物品。13=(2^0+2^1+2^2+6),或者說1、2、4、6可以組成1——13中的任何數字,所以,這4個數字可以代替1——13
那麼**如下:
for (int i=1;i<=n;i++)
if (w[i]*a[i]>c){//如果物品夠多,其實就是完全揹包問題
for (int c=0;c<=c;c++)//完全揹包
if (c>=w[i]) f[c]=max(f[c],f[c-w[i]]+v[i]);
else {
int k=1,ant=a[i];
while(k//是否去乙個重量為k*w[i],價值為k*v[i]的物品?
for (int c=c;c>=k*w[i];c--)
f[c]=max(f[c],f[c-k*w[i]]+k*v[i]);
//繼續分割
ant-=k;k+=k;
//吧剩下的作為單獨乙個物品
for (int c=c;c>=ant;c--)
f[c]=max(f[c],f[c-ant*w[i]]+ant*v[i]);
四、混合揹包
問題描述:還是揹包問題,只是有的物品只能取一次(0/1揹包),有的物品能去無限次(完全揹包),有的物品只能取有限次(多重揹包)。如何解決?
分析:額~~這道題不就是前三題的綜合嗎~~只不過再加個判斷罷了,其他就是模板啊!那麼具體偽**如下:
for (int i=1;iif (物品屬於0/1揹包)
//0/1揹包解法
else if (物品屬於完全揹包)
//完全揹包解法
else if (物品屬於多重揹包)
//多重揹包解法
怎麼樣??這種操作高階吧??
好,那麼今天的揹包還是就複習到這裡,這四種揹包還是非常重要的!
揹包九講之 01揹包
01揹包是最基礎的揹包問題,其中01代表的就是第i個物品的選或不選,在此先設v i 為體積,w i 為價值。很顯然,我們可以使用二位陣列dp i j 來表示前i個物品在揹包容量為j的時候可存放的最大價值。首先dp 0 0 0是很顯然的。而計算dp i j 時,存在01兩種情況 選或不選第i件物品。1...
揹包九講之 完全揹包
完全揹包與01揹包的區別在於完全揹包第i件物品可以在允許範圍內選無數個,同樣的v i 表示體積,w i 表示價值。同樣的,我們先從二維入手,較為顯而易見。dp i j 表示前i件物品在容量為j的最大價值,那麼相應的也會出現很多情況 1.不選 dp i j dp i 1 j 2.選一件 dp i j ...
揹包學習之揹包九講
做了一些icpc題目,感受到動態規劃的重要性,在此學習揹包 參考至部落格揹包九講 問題 n個物品 體積和價值分別為v i w i 和乙個體積為v的揹包,求揹包裝到的最大價值 狀態陣列 dp i j 為選前i個所用體積為j的最大價值 for int i 1 i n i for int j 1 j v ...