01背包
有 N N N 件物品和一个最多能背重量为 W W W 的背包。第 i i i 件物品的重量是 w e i g h t [ i ] weight[i] weight[i],得到的价值是 v a l u e [ i ] value[i] value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
利用动规五部曲进行求解:
-
确定dp数组以及下标的含义
使用二维数组 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从下标[0-i]的物品里任意取,放进容量为 j 的背包中的最大价值总和。 -
确定递推公式
动态规划的思想是从上一状态推出当前状态,从 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j] 状态来推 d p [ i ] [ j ] dp[i][j] dp[i][j],即在 $dp[i-1][j] 状态下考虑物品 状态下考虑 物品 状态下考虑物品i$ 的取舍:- 不取物品 i i i: 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:此时背包要留出物品i的重量,所以要找到 从下标
[
0
−
(
i
−
1
)
]
[0-(i-1)]
[0−(i−1)]的物品中任意取,放进容量
(
j
−
w
e
i
g
h
t
[
i
]
)
(j-weight[i])
(j−weight[i])的背包中的最大价值总和,然后再将物品
i
i
i放入背包,
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
w
e
i
g
h
t
[
i
]
]
+
v
a
l
u
e
[
i
]
dp[i][j] =dp[i-1][j-weight[i]] + value[i]
dp[i][j]=dp[i−1][j−weight[i]]+value[i]。
最终结果是这两种情况下的最大价值:
d p [ i ] [ j ] = max { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] } dp[i][j] = \max{\{dp[i-1][j], dp[i-1][j-weight[i]] + value[i] \}} dp[i][j]=max{dp[i−1][j],dp[i−1][j−weight[i]]+value[i]}
-
dp数组初始化
从定义出发,当背包的重量为0时,无法选取任何物品,即对于 d p [ i ] [ 0 ] dp[i][0] dp[i][0]来说全部等于0;
当仅考虑物品0时,只有当背包的重量大于 w e i g h t [ 0 ] weight[0] weight[0]时才能选取物品0,即对于 d p [ 0 ] [ j ] dp[0][j] dp[0][j]来说,当 j < w e i g h t [ 0 ] j<weight[0] j<weight[0]时, d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0;当 j ≥ w e i g h t [ 0 ] j≥weight[0] j≥weight[0]时, d p [ 0 ] [ j ] = v a l u e [ 0 ] dp[0][j]=value[0] dp[0][j]=value[0]。//声明dp数组,并初始化所有元素=0 vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0)); //初始化do[0][j] for (int i = weight[0]; i <= bagWeight; i++) { dp[0][i] = value[0]; }
-
确定遍历顺序
由递推公式来看,先遍历物品和先遍历背包均可以,但是先遍历物品更好理解。
-
举例推导
int bag01() {
vector<int> weight = { 1, 3, 4 };
vector<int> value = { 15, 20, 30 };
int bagWeight = 4;
int wsize = weight.size();
int vSize = value.size();
vector<vector<int>> dp(wsize + 1, vector<int>(bagWeight + 1, 0));
//初始化
for (int i = weight[0]; i <= bagWeight; i++) {
dp[0][i] = value[0];
}
//遍历
for (int i = 1; i < wsize; i++) {
for (int j = 0; j <= bagWeight; j++) {
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[wsize - 1][bagWeight] << endl;
return 0;
}