一、课程目标
- 背包问题
- 01背包
- 动态规划
- 过程理解
- 关键代码
二、目标详解
1、背包问题
基本模型:一个容量为V的背包,在一定的限制条件下,放进最多(或最少)价值的东西。
根据限制条件的不同,分为三种情况:
- 01背包(ZeroOnePack):每种物品只有一件,即只能选择放或者不放
- 完全背包(CompletePack):每种物品有无限件
- 多重背包(MultiplePack):每种物品最多有n[i]件可用
2、01背包动态规划
基本模型:一个容量为V的背包与N件物品,第i件物品的体积是c[i],价值为w[i],求将哪些物品装入背包可使得价值总和最大。
维度
为:i件物品、j容量的背包
定义状态
:设dp[i][j]表示把i件物品放入容量j的背包可获得的最大价值。
对于第i件物品(体积为c[i],价值为w[i]):
- 不放到背包里,则最大价值为dp[i-1][j]
- 放到背包里,则最大价值为dp[i-1][j-c[i]] + w[i]
状态转移方程
为:
- 初始化:dp[0][j] = 0, dp[i][0] = 0
- j < c[i]:dp[i][j] = dp[i-1][j]
- j>=c[i]:dp[i][j] = max(dp[i-1][j], dp[i-1][j-c[i]] + w[i])
3、理解过程
假设背包容量V=8,物品数量N=4:
物品编号 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
体积c | 2 | 3 | 4 | 5 |
价值w | 3 | 4 | 5 | 6 |
3.1 第一步:初始化
- dp[i][0]和dp[0][j]都为0
- 前两列体积c和价值w,为方便查询
c | w | i\j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|---|---|
- | - | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 3 | 1 | 0 | ||||||||
3 | 4 | 2 | 0 | ||||||||
4 | 5 | 3 | 0 | ||||||||
5 | 6 | 4 | 0 |
3.2 第二步:怎么填?
- 1的列:由于1 < c[1](体积为2)所以dp[1][1] = dp[1-1][1] = 0
- 同样,dp[2][1]、dp[3][1]、dp[4][1]等都是0
- dp[1][2]:由于2==c[1], dp[1][2]=max(dp[1-1][2], dp[1-1][2-2] + 3) = 3
- 理解:把1物品放进去,体积为2,获得价值为3
- dp[2][2]:由于2<c[2], dp[2][2] = dp[2-1][2] = 3
- 理解:2物品放不进去,所以还是只能放一个1物品
- ….依次类推到dp[1][3]、dp[1][4]…、dp[1][8] 都为3
c | w | i\j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|---|---|
- | - | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 3 | 1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
3 | 4 | 2 | 0 | 0 | 3 | ||||||
4 | 5 | 3 | 0 | 0 | 3 | ||||||
5 | 6 | 4 | 0 | 0 | 3 |
3.3 第三步:dp[2][3]
dp[2][3] = max(dp[2-1][3], dp[2-1][3-c[2]]+w[2])=max(3, 0+4)=4
- 理解:物品1或物品2都可以放进去,选择价值大的:
- 物品2放进去,则剩余容量为0,为dp[1][0] + w[2]=4
- 物品2不放进去,为dp[1][3]=3
c | w | i\j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|---|---|
- | - | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 3 | 1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
3 | 4 | 2 | 0 | 0 | 3 | 4 | |||||
4 | 5 | 3 | 0 | 0 | 3 | ||||||
5 | 6 | 4 | 0 | 0 | 3 |
dp[2][3]更直观的理解:
- 如果放进去
- 本列第一行的3,减去本行的体积列(c[i]),结果为0
- 找到上一行的0列的值,值为0
- 0加上本行的价值列(w[i]),结果为4
- 如果不放进去:取上一行的本列的,值为3
- dp[2][3]填写4和3的最大值4
3.4 最后结果,按以上理解逐步填写
c | w | i\j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|---|---|
- | - | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 3 | 1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
3 | 4 | 2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 |
4 | 5 | 3 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 9 |
5 | 6 | 4 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
最后,dp[4][8] = 10
4、关键代码
for(int i=1; i<=N; i++)
for(int j=1; j<=V; j++) {
if(j >= c[i])
dp[i][j] = max(dp[i-1][j], dp[i-1][j-c[i]] + w[i]);
else
dp[i][j] = dp[i-1][j];
}