yxc在b站上講的揹包九講:揹包九講專題
以及一篇非常經典的dd大牛的《揹包九講》
0 1揹包問題
有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i](本題裡是v[i]),價值是w[i]。
這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放。在求狀態轉移方程的方面,思路是集合劃分:
f(i,j):「在i個東西裡面選質量為j的東西的總商品價值」這一集合可分為「選的所有東西裡面不包含i」和「選的東西裡面包含i」兩種情況。
的話不含i的情況即是f(i-1,j)【在i-1個東西中選質量為j的東西】
含i的情況即是f(i-1,j-vi)+wi【由於選了i,那就是在i-1個東西中選j-vi質量的總價值加上i的價值】
將上述兩個集合取價值最大的取法,即為「在i個東西裡面選質量為j的東西的總商品價值」
優化1:減少操作次數
由於上述的情況中,含i的情況是不一定存在的(那是當揹包最大重量ji即裝不下的時候不需要考慮)
優化2:將二維陣列優化為滾動陣列
滾動陣列:如果f(i)的計算僅僅只用了f(i-1)來完成計算的話,就只需要開乙個f[2][n]的陣列即可(可以運用e=1-e來實現滾動)值得注意的是,由於本題中可以通過容量這一列從最大容量到最小容量的遍歷方法實現含i的情況在不含i的情況之後被更新(如果從最小容量到最大容量遍歷的話,j-vi是恆小於j的,在更新到j-vi時仍然是i-1的資料),故這題可以只開一維陣列實現
dp部分**如下:
for
(int i =
1; i <= n; i ++
)for
(int j = m; j >= v[i]
; j --
)//容量從大到小遍歷
f[j]
=max
(f[j]
, f[j - v[i]
]+ w[i]);
//v、w陣列分別是體積和價值陣列
完全揹包問題
有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。
這個問題非常類似於01揹包問題,所不同的是每種物品有無限件。也就是從每種物品的角度考慮,與它相關的策略已並非取或不取兩種,而是有取0件、取1件、取2件……等很多種。樸素演算法:
由於有每種物品都有無限件可以取用,所以還需要列舉每種物品選了多少件(列舉件數不能超過揹包容量)
for
(int i=
1;i<=n;i++
)for
(int j=
0;j<=m;j++
)for
(int k=
0;k*v[i]
<=j;k++
) f[i]
[j]=
max(f[i]
[j],f[i-1]
[j-v[i]
*k]+w[i]
*k);
優化1:通過展開化簡式子分別將f[i,j]和f[i,j-v]展開,可以發現f[i,j]計算式可被化簡為f[i,j]=max(f[i-1,j],f[i,j-v]+w[i]
優化2:將二維陣列優化為滾動陣列
這個優化和0 1揹包在儲存方式上的優化基本一致,分析如下:
0 1揹包和完全揹包問題的狀態轉移區別如下圖
0 1揹包優化為一維陣列是要倒過來遍歷的原因是因為j-vi是恆小於j的,如果從最小容量到最大容量遍歷的話,j-vi是恆小於j的,在更新到j-vi時變成了i的資料。這符合狀態轉移方程的要求。
dp部分**如下:(與0 1揹包問題非常相似)只是揹包容量的遍歷順序不同
for
(int i =
1; i <= n; i ++
)for
(int j = v[i]
; j <= m; j ++
)//容量從小到大遍歷
f[j]
=max
(f[j]
, f[j - v[i]
]+ w[i]);
//v、w陣列分別是體積和價值陣列
多重揹包問題
有n種物品和乙個容量為v的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。
這題目和完全揹包問題很類似,特點是:每種物品都有自己特異的件數、花費、價值。樸素演算法:
每種物品有n[i]件可以取用,需要列舉每種物品選了多少件(列舉件數不能超過揹包容量)
for
(int i=
1;i<=n;i++
)for
(int j=
0;j<=m;j++
)for
(int k=
0;k<=s[i]
&&k*v[i]
<=j;k++
)//與完全揹包相比僅僅是加了乙個判斷條件而已
f[i]
[j]=
max(f[i]
[j],f[i-1]
[j-v[i]
*k]+w[i]
*k);
樸素演算法的時間效率很低,通過下面的二進位制優化可以把遍歷每種物品的n[i]件物品的時間複雜度從o(n)優化為o(log n)
優化:通過展開化簡式子不可行,換用二進位制優化方式
詳見多重揹包問題的二進位制優化
分組揹包問題
有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i],價值是w[i]。這些物品被劃分為若干組,每組中的物品互相衝突,最多選一件(每組的數量)。
本問題在狀態轉移方面就只需要遍歷每一組中的元素,存在不選,選第乙個,選第二個……多種情況狀態轉移分析過程如下:
對每一種取法進行遍歷
dp部分**為:
(分組揹包問題的費用(體積)和價值都是二維存放)
for(int i =
1; i <= n; i ++
)for
(int j = m; j >=
0; j --
)for
(int k =
0; k < s[i]
; k ++
)//遍歷每一種取法
if(v[i]
[k]<= j)
f[j]
=max
(f[j]
, f[j - v[i]
[k]]
+ w[i]
[k])
;
動態規劃 揹包問題
給定n個物品,重量是,價值是,包的容量 承重 是w 問,放入哪些物品能使得包內價值最大 1 需要將問題轉化為子問題,通過遞迴實現,且子問題必然與父問題存在關聯 2 定義v i,j 表示為,當item取自前i個items且揹包capacity j 時,揹包問題的最優解,也即最高的價值。3 從前i個it...
動態規劃 揹包問題
不廢話,直接上 動態規劃,揹包問題。輸入為 int n 物品的種類數。int n weight 各件物品的重量。int n value 各種物品的價值。int w 揹包最大的裝載重量。輸出 v n b 的值,最大的裝載價值。x n 各類物品的裝載數量。author huangyongye publi...
動態規劃 揹包問題
1 開心的金明 問題描述 金明今天很開心,家裡購置的新房就要領鑰匙了,新房裡有一間他自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說 你的房間需要購買哪些物品,怎麼布置,你說了算,只要不超過n 元錢就行 今天一早金明就開始做預算,但是他想買的東西太多了,肯定會超過媽媽限定的n 元。於是,他把每...