一、01背包問題
1、概述
- 01背包中的0和1指的是放與不放,而且不能出現(xiàn)放多個的情況,背包只能放相同物品中的一個;
- 首先是對 d [ i ] [ j ] d[i][j] d[i][j] 數(shù)組的解釋,該數(shù)組表示的是只看前 i i i 個物品,總體積是 j j j 的情況下,總價值最大是多少;
2、過程模擬
- 不選第 i i i個物品,只考慮前 i ? 1 i-1 i?1個物品, d p [ i ] [ j ] = d p [ i ? 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i?1][j]
- 選第 i i i個物品, d p [ i ] [ j ] = d p [ i ? 1 ] [ j ? v [ i ] ] dp[i][j]=dp[i-1][j-v[i]] dp[i][j]=dp[i?1][j?v[i]]
- d p [ i ] [ j ] = m a x { 1 , 2 } dp[i][j]=max\{1,2\} dp[i][j]=max{1,2}
- 初始條件,一個物品都不考慮 d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0
背包的最大容量為 6 6 6。
物品 | 體積 v v v | 價值 w w w |
---|---|---|
A A A | 2 2 2 | 3 3 3 |
B B B | 3 3 3 | 5 5 5 |
C C C | 4 4 4 | 6 6 6 |
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | ||||||
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | ||||||
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
?
\Downarrow
?
?
\bullet
?對于每一個單元格
i
.
w
e
i
g
h
t
>
j
i.weight>j
i.weight>j是否成立,按行填寫
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | ||||||
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
? \Downarrow ?
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
? \Downarrow ?
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 | 0 | 3 | 5 | 6 | 8 | 9 |
滾動dp一維數(shù)組版
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
? \Downarrow ?
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
? \Downarrow ?
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
? \Downarrow ?
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 | 0 | 3 | 5 | 6 | 8 | 9 |
二、完全背包問題
1、概述
有
n
n
n件物品,每件物品的重量為
w
[
i
]
w[i]
w[i],價值為
c
[
i
]
c[i]
c[i]?,F(xiàn)有一個容量為
V
V
V,的背包,問如何選取物品放入背包,使得背包物品的總價值最大。其中每件物品有無窮件。
既然這樣,不妨像0-1背包問題那樣,先寫出狀態(tài)轉(zhuǎn)移方程,從源頭上摸索。
2、閆氏dp分析完全背包問題
d p { 狀態(tài)表示 ( i , j ) { 集合:所有只從前 i 個物品中選,總體積不超過 j 的方案的集合 屬性: m a x 狀態(tài)計算 d p [ i ] [ j ] = m a x ( d p [ i ? 1 ] [ j ] , f [ i ? 1 ] [ j ? v ] + w 、 f [ i ? 1 ] [ j ? 2 v ] + 2 w 、 . . . . . . ) , d p [ i ] [ j ? v ] = m a x ( d p [ i ? 1 ] [ j ? v ] , f [ i ? 1 ] [ j ? 2 v ] + w 、 f [ i ? 1 ] [ j ? 3 v ] + 2 w 、 . . . . . . ) + w ,兩式組合 d p [ i ] [ j ] = m a x ( d p [ i ? 1 ] [ j ] , f [ i ] [ j ? v ] + w ) 如下圖選第 i 個物品 dp\begin{cases} 狀態(tài)表示(i,j)\begin{cases} 集合:所有只從前i個物品中選,總體積不超過j的方案的集合 \\ 屬性:max \end{cases} \\ 狀態(tài)計算dp[i][j]=max(dp[i-1][j],f[i-1][j-v]+w、f[i-1][j-2v]+2w、......),dp[i][j-v]=max(dp[i-1][j-v],f[i-1][j-2v]+w、f[i-1][j-3v]+2w、......)+w,兩式組合dp[i][j]=max(dp[i-1][j],f[i][j-v]+w)如下圖選第i個物品 \end{cases} dp? ? ??狀態(tài)表示(i,j){集合:所有只從前i個物品中選,總體積不超過j的方案的集合屬性:max?狀態(tài)計算dp[i][j]=max(dp[i?1][j],f[i?1][j?v]+w、f[i?1][j?2v]+2w、......),dp[i][j?v]=max(dp[i?1][j?v],f[i?1][j?2v]+w、f[i?1][j?3v]+2w、......)+w,兩式組合dp[i][j]=max(dp[i?1][j],f[i][j?v]+w)如下圖選第i個物品?
3、過程模擬
例如:
容量j | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
組號 | 物品 | 體積v | 價值w | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | (無) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 小古銀手辦 | 2 | 1 | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 |
2 | 平板電腦 | 3 | 3 | 0 | 0 | 1 | 3 | 3 | 4 | 6 | 6 |
3 | 筆記本電腦 | 4 | 5 | 0 | 0 | 1 | 3 | 5 | 5 | 6 | 8 |
4 | 無價之寶 | 5 | 0 | 0 | 0 | 1 | 3 | 5 | 5 | 6 | 8 |
規(guī)律:
?
\bullet
?當
j
<
v
i
j<v_i
j<vi?的時候,
w
i
,
j
=
w
i
?
1
,
j
w_{i,j}=w_{i-1,j}
wi,j?=wi?1,j?(解釋:如果當前物品裝不進背包,最大價值和前
i
?
1
i-1
i?1個物品的最大價值一樣)
?
\bullet
?當
j
≥
v
i
j\ge v_i
j≥vi?的時候,
w
i
,
j
=
m
a
x
(
w
i
?
1
,
j
w_{i,j}=max(w_{i-1,j}
wi,j?=max(wi?1,j?不裝,裝
)
)
)(解釋:如果裝的下,在裝和不裝中選最大價值)
代碼模板
int m = 0;
int n = 0;
cin >> m >> n;
int v[40] = {};
int w[40] = {};
for (int i = 1; i <= n; i ++){
cin >> v[i] >> w[i];
}
int dp[40][210] = {};
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
if (j < v[i]) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i])
}
}
}
cout << "max = " << dp[n][m] <<endl;
優(yōu)化版代碼:
int m = 0;
int n = 0;
cin >> m >> n;
int v[40] = {};
int w[40] = {};
for (int i = 1; i <= n; i ++){
cin >> v[i] >> w[i];
}
int dp[40][210] = {};
for (int i = 1; i <= n; ++ i) {
for (int j = v[i]; j <= m; ++ j) {
dp[j] = max(dp[j], dp[j - v[i]] + w[i])
}
}
cout << "max = " << dp[n][m] <<endl;
三、多重背包問題
1、概述
求解將哪些物品裝入背包,可使物品體積總和不超過背包容量,且價值總和最大,但要注意的是,每件要取物品不能超過他給出的最大數(shù)量。
2、過程模擬
for(int i = 0; i < n; i ++)
for(int j = m; j >= v[i]; j --)
dp[j] = max(dp[j], dp[j - v[i]] + w[i], dp[j - 2 * v[i]] + 2 * w[i],......)//每件物品可以不去,可以取1個,或者取2個等等。
3、多重背包問題的優(yōu)化版本
假設(shè)有一種物品有 s s s 件,若要將其拆分開來,則從 1 1 1 開始循環(huán),每進行一次循環(huán)就乘 2 2 2,并每循環(huán)一次就減去迭代的變量 i i i,代碼如下:
while (n--) {
int v, w, s;
scanf("%d%d%d", &v, &w, &s);
for (int i = 1; i <= s; i *= 2) {
s -= i;
goods.push_back({ v * i,w * i });
}
if (s > 0)goods.push_back({ v * s,w * s });
}
分組背包問題
1、概述
有 N N N組物品和一個容量是 V V V的背包。每組物品有若干個,同一組內(nèi)的物品最多只能選一個。每件物品的體積是 v i j v_{ij} vij?,價值是 w i j w_{ij} wij?,其中 i i i是組號, j j j是組內(nèi)編號。
2、過程模擬
例如:
?
\bullet
?一個組只能選一個物品文章來源:http://www.zghlxwxcb.cn/news/detail-854940.html
組號 | 物品 | 體積v | 價值w |
---|---|---|---|
1 | 小古銀手辦 | 2 | 1 |
平板電腦 | 3 | 3 | |
2 | 筆記本電腦 | 4 | 5 |
3 | 無價之寶 | 5 | 0 |
以下是動態(tài)模擬:
?
\bullet
?每個組都有裝和不裝兩種情況
?
\bullet
?如果裝某個組的話,這個組只能裝一次文章來源地址http://www.zghlxwxcb.cn/news/detail-854940.html
容量j | ||||||||
---|---|---|---|---|---|---|---|---|
組號 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | |||||||
2 | 0 | |||||||
3 | 0 |
3、代碼演示
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int n, m;
int v[N], w[N], dp[N];
int main() {
scanf("%d%d", &n, &m);
while (n--) {
int s;
scanf("%d", &s);
for (int i = 0; i < s; i++)
scanf("%d%d", &v[i], &w[i]);
for (int j = m; j >= 0; j--) {
for (int k = 0; k < s; k++) {
if (j >= v[k]) {
dp[j] = max(dp[j], dp[j - v[k]] + w[k]);
}
}
}
}
printf("%d", dp[m]);
return 0;
}
到了這里,關(guān)于Acwing-基礎(chǔ)算法課筆記之動態(tài)規(guī)劃(背包問題)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!