一、0-1背包问题
1.1 适用场景
0-1背包问题属于背包问题中的一种,其特点是:每个物品只能被选择一次,两种状态即要么装入背包,要么不装入背包。
1.2 问题描述
有一个背包,其容量为m
现有n
个物品,每个物品的重量为w[i]
,价值为v[i]
现在需要选择一些物品装入背包,使得背包中物品的总价值最大。
1.3 通用代码思路
1.3.1 二维数组方式
数组含义
dp[i][j]
表示前i个物品在背包容量为j时的最大价值
状态转移方程
- 当
j<w[i]
时,即当前物品的重量大于背包容量,此时无法装入背包,因此dp[i][j]=dp[i-1][j]
- 当
j>=w[i]
时,即当前物品的重量小于等于背包容量,此时可以选择装入或者不装入背包,因此dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
通用代码
1. 初始化
通常初始化第一排
2. 遍历顺序
可以采用先物品后背包
也可以采用先背包后物品
3. 背包的遍历顺序
正序就行
1 |
|
1.3.2 一维数组方式
数组含义
dp[j]
表示背包容量为j时的最大价值
状态转移方程
- 当
j>=w[i]
时,即当前物品的重量小于等于背包容量,此时可以选择装入或者不装入背包,因此dp[j]=max(dp[j],dp[j-w[i]]+v[i])
通用代码
1. 初始化
可以不用初始化(全初始化为0)
2. 遍历顺序
必须采用先物品后背包的遍历顺序
3. 背包的遍历顺序
由于要求每个物品只能被选择一次,且状态转移方程是由前面的状态推导出来的
因此背包的遍历顺序必须是逆序的,即从大到小遍历,否则会出现重复选择的情况
1 | for(int i = 0; i < n; ++i){//物品 |
二、完全背包问题
2.1 适用场景
完全背包问题的特点是:每个物品可以被选择多次,两种状态即装入背包或者不装入背包
2.2 问题描述
有一个背包,其容量为m
现有n
个物品,每个物品的重量为w[i]
,价值为v[i]
现在需要选择一些可重复的物品装入背包,使得背包中物品的总价值最大。
2.3 通用代码思路-一维数组方式
2.3.1 数组含义
dp[j]
表示背包容量为j时的最大价值
2.3.2 状态转移方程
- 当
j>=w[i]
时,即当前物品的重量小于等于背包容量,此时可以选择装入或者不装入背包,因此dp[j]=max(dp[j],dp[j-w[i]]+v[i])
2.3.3 通用代码
1. 初始化
可以不用初始化(全初始化为0)
2. 遍历顺序
可以采用先物品后背包
也可以采用先背包后物品
3. 背包的遍历顺序
由于要求每个物品可以被选择多次,所以允许前面的状态中也包含该物品
因此背包的遍历顺序必须是正序的,即从小到大遍历
先遍历物品,再遍历背包
1
2
3
4
5for(int i = 0; i < n; ++i){//物品
for(int j = w[i]; j <= m; ++j){//背包
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}先遍历背包,再遍历物品
1
2
3
4
5for(int j = w[i]; j <= m; ++j){//背包
for(int i = 0; i < n; ++i){//物品
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}