这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
动态规划
什么是动态规划?动态规划就是将一个大问题不断向下拆分成小问题,直到拆分出的小问题可以求出其解,然后将小问题的解不断的向上合并,最终得到大问题的解决方案。由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中
01背包
给定n种物品和一背包。物品 i 的重量似乎 wi,其价值为 vi,背包的容量为 c。
问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
简单思路
1.01背包问题与背包问题的区别在于,01背包,物品的选择只有两种一种是拿,另一种是不拿,而背包问题在于,物品可以只取一部分。所以01背包问题不能用贪心算法解决。
2.以dp[i][j]表示用i种物品,重量为j表示所取得的价值。
3.对于第i种物品,如果第i种物品重量大于j,就证明第i种物品肯定不能取,这时的dp[i][j]=dp[i-1][j]
4.如果第i种物品重量小于j,那就会出现两种情况,采用i的话,物品价值dp[i][j]=采用前面的i-1种物品,所占用的重量为j-i.getweight,所产生的价值+第i 种物品的价值。如果不采用i,价值为dp[i-1][j]。换成数学表达式就是dp[i][j]=Math.max(dp[i-1][j-weight]+value,dp[i-1][j]);
5.比如当i=5,j=10时,dp[5][10]就代表了所取得的最大价值。到这里我们就完成了任务的一半,接下为我们要寻找到底哪些物品放入了背包,从前面的表达式我们可以发现,当dp[i][j]=dp[i-1][j-weight]时,这时为i的物品就会放入背包,所以我们从结果,开始往回走,遇到这种情况,就说明有物品放入背包,然后物品数减1,重量减去为i的重量,继续,最后就能求出哪 些物品放入背包了。
参数
物品个数n = 3
背包容量c = 4
物品对应的价值数组 value[i] = [30,20,15]
物品对应的重量 weight[i] = [4,3,1]
构建表格
| 物品/容量 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 物品A(4KG) | 0 | 0 | 0 | 30 |
| 物品B(3KG) | 0 | 0 | 20 | 30 |
| 物品C(1KG) | 15 | 15 | 20 | 35 |
伪代码解析
1.初始化二维数组
maxValue[n+1][c+1] //初始化数组时多构建一行一列,可防止数组越+代码的可读性
2.网格构建 (主要是首行首列需要填充为0)
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= c; j++) {
maxValue[i][j] = 0;
}
}
3.网格填充
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= c; j++) {
int topValue = maxValue[i-1][j];//取上一个网格的值 (即同一列上一行)
//先判断当前商品的重量是否大于背包容量,如果大于,则取上一个网格即topValue的值
//如果背包容量足以容纳当前物品的重量,1.取当前价值+剩余空间价值(容量-当前重量)
//若相等,则取当前价值
int thisValue = weight[i-1]<=j?
(j-weight[i-1]?value[i-1]+maxValue[i-1][j-weight[i-1]]:value[i-1])
:topValue;
//比对上一格,取最大值
max[i][j] = topValue>thisValue?topValue:thisValue;
}
}
4.取数组最后一位则为最优