0 1揹包(詳解)

2021-07-25 04:02:47 字數 2619 閱讀 9880

0-1揹包問題:

有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

這個問題的特點是:每種物品只有一件,可以選擇放或者不放。

演算法基本思想:

利用動態規劃思想 ,子問題為:f[i][v]表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。

其狀態轉移方程是:f[i][v]=max    //這個方程非常重要,基本上所有跟揹包相關的問題的方程都是由它衍生出來的。

解釋一下上面的方程:「將前i件物品放入容量為v的揹包中」這個子問題,如果只考慮第i件物品放或者不放,那麼就可以轉化為只涉及前i-1件物品的問題,即1、如果不放第i件物品,則問題轉化為「前i-1件物品放入容量為v的揹包中」;2、如果放第i件物品,則問題轉化為「前i-1件物品放入剩下的容量為v-c[i]的揹包中」(此時能獲得的最大價值就是f [i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i])。則f[i][v]的值就是1、2中最大的那個值。

(注意:f[i][v]有意義當且僅當存在乙個前i件物品的子集,其費用總和為v。所以按照這個方程遞推完畢後,最終的答案並不一定是f[n] [v],而是f[n][0..v]的最大值。)

優化空間複雜度:

以上方法的時間和空間複雜度均為o(n*v),其中時間複雜度基本已經不能再優化了,但空間複雜度卻可以優化到o(v)。

上面f[i][v]使用二維陣列儲存的,可以優化為一維陣列f[v],將主迴圈改為:

for i=1..n

for v=v..0

f[v]=max;

即將第二層迴圈改為從v..0,逆序。

解釋一下:

假設最大容量m=10,物品個數n=3,物品大小w,物品價值p。

當進行第i次迴圈時,f[v]中儲存的是上次迴圈產生的結果,即第i-1次迴圈的結果(i>=1)。所以f[v]=max這個式子中,等號右邊的f[v]和f[v-c[i]]+w[i]都是前一次迴圈產生的值。

當i=1時,f[0..10]初始值都為0。所以

f[10]=max=max=max=4;

f[9]=max=max=max=4;

......

f[3]=max=max=max=4;

f[2]=max=max=0;//陣列越界?

f[1]=0;

f[0]=0;

當i=2時,此時f[0..10]經過上次迴圈後,都已經被重新賦值,即f[0..2]=0,f[3..10]=4。利用f[v]=max這個公式計算i=2時的f[0..10]的值。

當i=3時同理。

具體的值如下表所示:

因此,利用逆序迴圈就可以保證在計算f[v]時,公式f[v]=max中等號右邊的f[v]和f[v-c[i]]+w[i]儲存的是f[i-1][v]和f[i -1][v-c[i]]的值。

當i=n時,得到的f[v]即為要求的最優值。

初始化的細節問題:

在求最優解的揹包問題中,一般有兩種不同的問法:1、要求「恰好裝滿揹包」時的最優解;2、求小於等於揹包容量的最優解,即不一定恰好裝滿揹包。

這兩種問法,在初始化的時候是不同的。

1、要求「恰好裝滿揹包」時的最優解:

在初始化時除了f[0]為0其它f[1..v]均設為-∞,這樣就可以保證最終得到的f[n]是一種恰好裝滿揹包的最優解。如果不能恰好滿足揹包容量,即不能得到f[v]的最優值,則此時f[v]=-∞,這樣就能表示沒有找到恰好滿足揹包容量的最優值。

2、求小於等於揹包容量的最優解,即不一定恰好裝滿揹包:

如果並沒有要求必須把揹包裝滿,而是只希望價值盡量大,初始化時應該將f[0..v]全部設為0。 總結

01揹包問題是最基本的揹包問題,它包含了揹包問題中設計狀態、方程的最基本思想,另外,別的型別的揹包問題往往也可以轉換成01揹包問題求解。故一定要仔細體會上面基本思路的得出方法,狀態轉移方程的意義,以及最後怎樣優化的空間複雜度。

未進行空間優化**:

#include #include using namespace std;

const int min=0x80000000;

const int n=3; //物品數量

const int v=5; //揹包容量

int f[n+1][v+1];

int package(int *w,int *c,int n,int v);

void main(int argc,char *argv)

; //物品權重

int c[4]=; //物品大小

int result=package(w,c,n,v);

if(result>0)

; //物品權重

int c[4]=; //物品大小

int result=package(w,c,n,v);

if(result>0)

{ cout<=c[i];j--) //注意此處與解法一是順序不同的,弄清原因

{ f[j]=(f[j]>f[j-c[i]]+w[i])?f[j]:(f[j-c[i]]+w[i]);

cout<

01揹包詳解

看了2天的01揹包,感覺現在真的是懂了,記錄一下,這樣才能記得更加深刻,其實早就接觸過01揹包,當時一知半解的,今天看了書本和別人的部落格,真的很有用 1 描述一下01揹包問題 有n個重量和價值分別為wi,vi,的物品,從這些物品中挑選出總重量不超過w的物品,求所有的挑選方案中價值總和的最大值。這裡...

詳解01揹包

假設有乙個小偷,他帶了乙個揹包想偷東西,這個揹包的容量capacity 8。他可以偷的物品一共有四個,每個物品都有自己的價值和重量,每個物品都可以選擇放或者不放 放就得到1個物品,不放就得到0個物品,因此得名0 1揹包 那麼,在揹包可承受的最大重量為8的前提下,如何選取要偷的物品,使得所偷物品的總價...

01揹包,完全揹包,多重揹包詳解

揹包之01揹包 完全揹包 多重揹包詳解 ps 大家覺得寫得還過得去,就幫我把部落格頂一下,謝謝。首先說下動態規劃,動態規劃這東西就和遞迴一樣,只能找區域性關係,若想全部列出來,是很難的,比如漢諾塔。你可以說先把除最後一層的其他所有層都移動到2,再把最後一層移動到3,最後再把其餘的從2移動到3,這是乙...