前情提要
之前写了动态规划的相关文章,仅仅只是介绍了动态规划的相关概念,并没有细致深入的去分析动态规划的其他例子,作为动态规划最经典的便是01 背包问题,记得曾经听过这样一句话,所以有关动态规划的问题都可以转换成为01背包问题。
什么是01背包
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
为方便讲解和理解,下面讲述的例子均先用具体的数字代入,即:eg:number=4,capacity=8

思路详情
(1)把背包问题抽象化(x1,x2,x3...xn),其中xi取0或者1可以表示选或者不选,vi表示第i个物品的价值,wi表示第i个物品的体积(或重量)
(2)建立模型:max(v1x1+v2x2+....+vnxn)
(3)约束条件为(w1x1+w2x2+....wnxn) < capacity (capacity为包的体积)
(4)定义(vi,j): 当前背包容量为j,前i个最佳组合对应的价值
(5)最优性原理是动态规划重的基础,不论初始状态,初始决策如何,对于前面决策所造成的某一状态而言,其后的各阶段决策必须形成最优
假设 OPT(x1,x2,...,xn)
肯定存在OPT(x2,x3...,xn)
再假设:(Y1,Y2,...Y3)是上述子问题的最优解,则应该有的是
(v2x2+v1x1+....vnxn)+v1x1 < (v2Y2+v3Y3+....vnYn)+v1x
(6)寻找递推关系式
① 包的容量比该商品小,装不下,此时的价值与前i-1个价值一样
V(i,j) = v(i-1,j)
② 有足够容量为装该商品,但装了也不一定能够达到最优解,在装与不装中选择最优的那个
v(i,j) = max{v(i-1,j);v(i-1;j-w(i)+v(i))} {装不了;装了}
下面我们列一个相关的表格 i为前i个最佳组合,j为当前背包容量,表格中意味着,当前的最大价值
i/j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 |
3 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 8 | 9 |
4 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
/**
*
* @param capacity 背包容量
* @param number 有几个物品
* @param weight 物品重量数组
* @param dp dp数组
* @param value 物品价值数组
*/
void findMax(int capacity, int number, int[] weight, int[][] dp, int[] value) {
int i, j;//j为背包剩余容量,i为第i个物品
//第0行我们统一填的0
for (i = 1; i < number; i++) {
for (j = 1; j <= capacity; j++) {
//如果包装不进的话
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else {
//能装的话
dp[i][j] = Math.max(dp[i - 1][j], (dp[i - 1][j - weight[i]]) + value[i]);
}
}
}
}
(7)仅仅把表格填完,最优解就是dp[4][8] = 10 ,需要回溯找出解的组成
① dp[i][j] == dp[i-1][j] 时,证明没有选择该i个商品,这个时候去到dp[i-1][j]
② dp[i][j] == dp[i-1][j-weight[i]]+value[i]时,说明装了第i个商品,该商品为最优解的一部分,所以我们需要回溯到包装前dp[i-1][j-weight[i]]
③ 一直遍历到i=0结束为止,所有解的组成都能够找到
/**
*
* @param i 前i个商品
* @param j 体积
* @param dp 上一步得到的动态规划数组
*/
void findWhat(int i , int j,int[][] dp ){
if (i>=0){
if (dp[i][j]==dp[i-1][j])//没变
{
item[i]=0;//全局变量标记未选中
findWhat(i-1,j,dp);
}else if (j-weight[i]>0&&dp[i][j]==dp[i-1][j-weight[i]]+value[i]){
item[i]=1;//标记已经被选中
findWhat(i-1,j-weight[i],dp);
}
}
}
总结
这是动态规划一类比较经典的问题,很多都可以转换成为背包问题来解决,但背包问题也有很多变种,之前看过一篇pdf背包九讲,讲的很详细。希望能给你带来帮助哈
ps:最近太忙惹 都没时间更新博客 都调时间更新的呜呜呜呜呜 太难惹