揹包問題模板彙總

2021-09-25 10:04:36 字數 3483 閱讀 9611

完全揹包

多重揹包

混合揹包

揹包問題(knapsack problem)是一種組合優化的np完全問題。它是在2023年由merkel和hellman提出的。

問題的描述為:

有乙個揹包,最多放m kg的物體(物體大小不限);

有n個物體,每個物體的重量為wi,每個物體完全放入揹包後可獲得收益vi。問: 如何放置能獲得最大的收益?

揹包問題一般分為兩種,若每個物體不可拆分,則稱為0-1揹包問題(和其引申問題),這種問題無法用貪心法求的最優解,應該用動態規劃的思想。而若每個物體可以切分,則稱為一般揹包問題,可以使用貪心法求的最優解。

對於一般揹包問題,其思想就是貪心。

貪心策略:先將每一件物品權值與重量的比值按從大到小的順序排序,然後依次放入揹包,也就是價效比最高的先放入揹包。

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

這是最常見的揹包問題,其特點是:每種物品僅有一件,可以選擇放或不放。

用子問題定義狀態:即a[i][j]表示前i件物品恰放入乙個容量為j的揹包可以獲得的最大價值。

當不放的時候則是:a[i][j] = a[i-1][j];

放的時候則是:a[i][j] = a[i-1][j-w[i]]+v[i];

如果不放,就保持上一種狀態,如果放,就在犧牲容積的情況下增加價值。由於我們求的是最大價值,則其狀態轉移方程便是:

a[i][j]=max。

for

(int i=

1;i<=n;i++

)for

(int j=v;j>=

1;j--

)

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

先考慮上面講的基本思路如何實現,肯定是有乙個主迴圈i=1…n,每次算出來二維陣列f[i][0…v]的所有值。那麼,如果只用乙個陣列f [0…v],能不能保證第i次迴圈結束後f[j]中表示的就是我們定義的狀態f[i][j]呢?

f[i][j]是由f[i-1][j]和f [i-1][j-w[i]]兩個子問題遞推而來,能否保證在推導f[v]時(也即在第i次主迴圈中推f[j]時)能夠得到f[j]和f[j -w[i]]的值呢?事實上,這要求在每次主迴圈中我們以v=v…0的順序推f[j],這樣才能保證推f[j]時f[j-w[i]]儲存的是狀態f[i-1][j-c[i]]的值。

**如下:

for

(int i=

1;i<=n;i++

)for

(int j=v;j>=w[i]

;j--

)

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

這個問題非常類似於01揹包問題,所不同的是每種物品有無限件。也就是從每種物品的角度考慮,與它相關的策略已並非取或不取兩種,而是有取0件、取1件、取2件……等很多種。如果仍然按照解01揹包時的思路,令f[i][j]表示前i種物品恰放入乙個容量為j的揹包的最大權值。最終得出結論,完全揹包和0-1揹包的狀態方程是基本一致的,但是為什麼完全揹包的迴圈是正序[w[i],v],而0-1揹包的迴圈是倒序[v,w[i]],

這是因為完全揹包的特點恰是每種物品可選無限件,所以在考慮「加選一件第i種物品」這種策略時,卻正需要乙個可能已選入第i種物品的子結果f[i][j-w[i]],正序則正好滿足其條件。

for

(int i=

1;i<=n;i++

)for

(int j=

1;j<=v;j++

)

一維優化同0-1揹包:

for

(int i=

1;i<=n;i++

)for

(int j=w[i]

;j<=v;j++

)

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

與完全揹包一樣,多重揹包也是轉化為0-1揹包問題來做:把第i種物品換成n[i]件01揹包中的物品,則得到了物品數為σn[i]的01揹包問題,直接求解,時間複雜度為o(v*σn[i])。

for

(int i=

1;i<=n;i++

)for

(int j=v;j>=w[i]

;j--

)for

(int k=

1;k<=n[i]

&&j-k*w[i]

>=

0;k++

) f[j]

=max

(f[j]

,f[j-w[i]

*k]+v[i]

*k);

在多重揹包的問題中,很多時候σn[i]會非常大,很有可能超時。

因為1、2、4、8 、16 、 32……2 n 可以組成從1到2(n+1)-1中的任何數

用二進位制的思想,我們將第i種物品分成若干件物品,其中每件物品有乙個係數,這件物品的費用和價值均是原來的費用和價值乘以這個係數。使這些係數分別為1,2,4,…,2(k-1),n[i]-2 k +1,且k是滿足n[i]-2k+1>0的最大整數。例如,如果n[i]為13,就將這種物品分成係數分別為1,2,4,6的四件物品。

這樣就把原問題轉化為了複雜度為o(v*σlog n[i])的01揹包問題。

for

(int i=

1;i<=n;i++)if

(a[i]

.num>0)

//最後一項補齊

}

如果將0-1揹包、完全揹包、多重揹包混合起來。也就是說,有的物品只可以取一次(01揹包),有的物品可以取無限次(完全揹包),有的物品可以取的次數有乙個上限(多重揹包)。應該怎麼求解呢?

設p[i]=0,1,n(n!=0,1)分別為0-1揹包、完全揹包、多重揹包。

**如下:

#include

#include

#define maxn 10005

using

namespace std;

int t[maxn]

,c[maxn]

,p[maxn]

;int

main()

else

if(p[i]==1

)//01揹包

else

//多重揹包

} cout<;return0;

}

揹包問題模板

特點 每種物品只有一件 子問題定義狀態 bag i v 前i件物品放到乙個容量為v的揹包中可以獲得最大價值 轉移狀態方程 bag i v max bag i 1 v bag i 1 v weight i value i 模板 include include using namespace std i...

揹包問題模板

01揹包在時間複雜度上都是n n v 在這個基礎之上已經不能再進行優化了,在空間複雜度上,我們首先看一下複雜度為o n v 的程式 for int i 1 i n i for int j 0 j w j 但是我們還可以將空間複雜度壓縮為o v 我們會發現這裡每次更新第i層都只是看第i 1層,其他層的...

模板 揹包問題

include include define max a,b a b a b using namespace std const int n 1005 int n,v,v n w n int dp n voidf intmain f printf d n dp v return0 include i...