動態規劃之揹包問題

2022-05-16 14:25:08 字數 3614 閱讀 2888

\[揹包

\]概念

\(-揹包問題(knapsack problem)是一種組合優化的np完全問題。

\\問題可以描述為:給定一組物品,每種物品都有自己的重量和**,在限定的總重量內,我們如何選擇,才能使得物品的總**最高。

\\問題的名稱**於如何選擇最合適的物品放置於給定揹包中。

\\相似問題經常出現在商業、組合數學,計算複雜性理論、密碼學和應用數學等領域中。

\\也可以將揹包問題描述為決定性問題,即在總重量不超過w的前提下,總價值是否能達到v?

\\它是在2023年由merkle和hellman提出的。

\\-揹包問題已經研究了乙個多世紀,早期的作品可追溯到2023年數學家託比亞斯·丹齊格(tobias dantzig,1884-1956)的早期作品,並指的是包裝你最有價值或有用的物品而不會超載你的行李的常見問題。

\)應用

\(-2023年的石溪布魯克大學演算法庫的研究表明,在75個演算法問題中,揹包問題是第18個最受歡迎,第4個最需要解決的問題(前三為後kd樹,字尾樹和bin包裝問題)。

\\-揹包問題出現在各種領域的現實世界的決策過程中,例如尋找最少浪費的方式來削減原材料,選擇投資和投資組合,選擇資產支援資產**化,和生成金鑰為merkle-hellman和其他揹包密碼系統。

\\-揹包演算法的乙個早期應用是在測試的構建和評分中,測試者可以選擇他們回答哪些問題。

\\對於小例子來說,這是乙個相當簡單的過程,為測試者提供這樣的選擇。

\\例如,如果考試包含12個問題,每個問題的價值為10分,測試者只需回答10個問題即可獲得100分的最高分。

\\然而,在點值的異質分布的測試 - 即不同的問題值得不同的點值 - 更難以提供選擇。

\\feuerman和weiss提出了乙個系統,其中學生被給予乙個異質測試,共有125個可能的點。

\\學生被要求盡可能回答所有的問題。

\\在總點數加起來為100的問題的可能子集中,揹包演算法將確定哪個子集給每個學生最高的可能得分。

\)定義

\(-我們有n種物品,物品j的重量為w_j,**為p_j。

\\-我們假定所有物品的重量和**都是非負的。

\\揹包所能承受的最大重量為w。

\\-如果限定每種物品只能選擇0個或1個,則問題稱為0-1揹包問題。

\\可以用公式表示為:

\)\[最大化\ \ \ \sum_^np_jx_j

\]\[受限於\ \ \ \sum_^nw_jx_j\leqslant w,x_j\in\

\]\(

如果限定物品j最多只能選擇b_j個,則問題稱為有界揹包問題。

\\可以用公式表示為:

\)\[最大化\ \ \ \sum_^np_jx_j

\]\[受限於\ \ \ \sum_^nw_jx_j\leqslant w,x_j\in\

\]\(

如果不限定每種物品的數量,則問題稱為無界揹包問題。

\\各類複雜的揹包問題總可以變換為簡單的0-1揹包問題進行求解。

\)基礎揹包

題目\(

有n件物品和乙個容量為v的揹包。

\\第i件物品的重量是w[i],價值是v[i]。

\\求解將哪些物品裝入揹包可使這些物品的重量總和不超過揹包容量,且價值總和最大。

\)基本思路

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

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

\\則其狀態轉移方程便是:

\\f[i][v]=max\。

\\可以壓縮空間,f[v]=max

這個方程非常重要,基本上所有跟揹包相關的問題的方程都是由它衍生出來的。所以有必要將它詳細解釋一下:「將前i件物品放入容量為v的揹包中」這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為乙個只牽扯前i-1件物品的問題。如果不放第i件物品,那麼問題就轉化為「前i-1件物品放入容量為v的揹包中」,價值為f[i-1][v];如果放第i件物品,那麼問題就轉化為「前i-1件物品放入剩下的容量為v-w[i]的揹包中」,此時能獲得的最大價值就是f [i-1][v-w[i]]再加上通過放入第i件物品獲得的價值v[i]。

注意f[v]有意義當且僅當存在乙個前i件物品的子集,其費用總和為f[v]。所以按照這個方程遞推完畢後,最終的答案並不一定是f[n] [v],而是f[n][0..v]的最大值。如果將狀態的定義中的「恰」字去掉,在轉移方程中就要再加入一項f[v-1],這樣就可以保證f[n] [v]就是最後的答案。至於為什麼這樣就可以,由你自己來體會了。

空間複雜

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

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

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

for i=1..n

for v=v..0

f[v]=max;

其中的f[v]=max一句恰就相當於我們的轉移方程f[i][v]=max,因為的

f[v-w[i]]就相當於原來的f[i-1][v-w[i]]。如果將v的迴圈順序從上面的逆序改成順序的話,那麼則成了f[i][v]由f[i][v-w[i]]推知,與本題意不符,但它卻是另乙個重要的揹包問題p02最簡捷的解決方案,故學習只用一維陣列解01揹包問題是十分必要的。 [10]

\)以下**

//01二維揹包

#includeusing namespace std;

int main();

for(int i=1;i<=n;i++)

for(int j=t;j>=w[i];j--)

f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);

coutint main();

for(int i=1;i<=n;i++)

for(int j=t;j>=w[i];j--)

f[j]=max(f[j],f[j-w[i]]+v[i]);

coutint main();

for(int i=1;i<=n;i++)

for(int j=w[i];j<=t;j++)

f[j]=max(f[j],f[j-w[i]]+v[i]);

coutint main()

int t;

cin>>t;

int f[101]=;

for(int i=1;i<=k;i++)

for(int j=t;j>=w[i];j--)

f[j]=max(f[j],f[j-w[i]]+v[i]);

cout

}

動態規劃之揹包問題

最近刷題遇到好幾道揹包問題,揹包問題是動態規則中的一類體型,在考察演算法的筆試中經常遇到。關於揹包問題,文章 揹包問題九講 中已經做了很多分析,這裡就不再細述,建議好好看看這篇文章。然而文章給了許多案例分析,卻沒有很好的練習。說明 1 本文目的不在於講解揹包問題的分析與講解,而是收集了一些揹包問題。...

動態規劃之揹包問題

一 問題描述 有n 個物品,它們有各自的重量和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?二 總體思路 根據動態規劃解題步驟 問題抽象化 建立模型 尋找約束條件 判斷是否滿足最優性原理 找大問題與小問題的遞推關係式 填表 尋找解組成 找出01揹包問題的最優解以及解組成,然後編...

動態規劃之 揹包問題

前些天在做動態規劃的題,感覺動態規劃博大精深,沒有一種特定的模式,學起來很費勁。在這裡就動態規劃中的揹包問題談談。三種揹包問題 0 1揹包,完全揹包,多重揹包。0 1揹包 有n件物品和容量為v的揹包,求解將哪些物品放入揹包中可以使獲得的價值最大。f i v 表示將前i件物品恰好放入容量為v的揹包可以...