DP之背包问题+记忆递归
2011-07-05 20:39
459 查看
2个问题:
1)背包问题的动态规划解法
2)动态规划的另一种实现方式,记忆递归(dp的第一篇文章就提到过,professional中也提到过),在这里来讲解,加上全面所有的文章,这一点应该可以算是动态规
划里最后一个没有详细介绍的关键点了
---------------------------------------------------------------------------------------------------------------------------------------------------
给定一组物品:
重量为 w1 , w2 , .......wn
价值为 v1 , v2 , .........vn
和一个称重量为W的书包。
求这些物品的一个最有价值的子集,可以装到书包中去。
--------------------------------------------------------------------------------------------------------------------------------------
1,背包问题
设 V[ i , j ]表示能够放进称重量为 j 的背包的前 i 个物品的最有价值子集的价值,目标是求V[ n , W ]
根据 V[ i , j ] 的最佳子集中是否包含物品 i,可以得到下列递推式:
![](http://pic002.cnblogs.com/images/2011/282432/2011070521060758.jpg)
这个递推式的意思是:如果 i 的重量已经比 j 大了,那显然不含 i ( j-wi < 0 ), 如果 i 的重量比 j 小,那么可能包含 i (如果包含能去到最大值的话)。
![](http://pic002.cnblogs.com/images/2011/282432/2011070521092017.jpg)
这个表可以按行也可以按列填:
实现:
结果:
0 0 0 0 0 0
0 0 12 12 12 12
0 10 12 22 22 22
0 10 12 22 30 32
0 10 15 25 30 37
写了这么几个动态规划,已经可以发现,有了递推式后,其编程就显得非常easy,基本上就是照着公式操作矩阵。
因此,应重点关注动态规划的思想,怎么去描述和刻画问题,发现最有子结构,得到其状态转移方程。
-------------------------------------------------------------------------------------------------------------------------------------------------
2,记忆递归--动态规划的另一种实现方式
关于什么什么是记忆递归,它的出发点是什么,为什么要记忆递归,这些在前面都提过,这里再简单说下:
动态规划的核心思想之一就是记忆(或者记录)来避免对重复子问题进行求解,然而,它并没有避免对不必要子问题进行求解。
若将递归与动态规划结合起来,就可以得到一种动态规划的递归实现方式,这种方式避免了对不必要子问题进行求解。
实际上就是在递归的时候,在动态规划表中先检查要递归的项是否已经求出来了,如果已经求出来了,就直接返回答案,否则才去递归求解。
背包问题的记忆递归实现:
![](http://pic002.cnblogs.com/images/2011/282432/2011070521275858.jpg)
实际上,就是在V[ i , j]还没有求出来的时候(一旦一个V[ i , j]求出来了,就不会再变,这点很重要),才去递归,否则就直接返回值。
想想斐波拉契数列也可以记忆递归的去实现。
-------------------------------------------------------------------------------------------------------------------------------------------------
总结:
1) 背包问题的时间复杂度和空间复杂度都是 nW,2个循环,见代码
2)一个关键点:动态规划的另一种实现方式,记忆递归
1)背包问题的动态规划解法
2)动态规划的另一种实现方式,记忆递归(dp的第一篇文章就提到过,professional中也提到过),在这里来讲解,加上全面所有的文章,这一点应该可以算是动态规
划里最后一个没有详细介绍的关键点了
---------------------------------------------------------------------------------------------------------------------------------------------------
给定一组物品:
重量为 w1 , w2 , .......wn
价值为 v1 , v2 , .........vn
和一个称重量为W的书包。
求这些物品的一个最有价值的子集,可以装到书包中去。
--------------------------------------------------------------------------------------------------------------------------------------
1,背包问题
设 V[ i , j ]表示能够放进称重量为 j 的背包的前 i 个物品的最有价值子集的价值,目标是求V[ n , W ]
根据 V[ i , j ] 的最佳子集中是否包含物品 i,可以得到下列递推式:
![](http://pic002.cnblogs.com/images/2011/282432/2011070521060758.jpg)
这个递推式的意思是:如果 i 的重量已经比 j 大了,那显然不含 i ( j-wi < 0 ), 如果 i 的重量比 j 小,那么可能包含 i (如果包含能去到最大值的话)。
![](http://pic002.cnblogs.com/images/2011/282432/2011070521092017.jpg)
这个表可以按行也可以按列填:
实现:
package Section8; /*第八章 动态规划 背包问题*/ public class BackPack { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] w = { 2, 1, 3, 2 }; // 重量数组 int[] v = { 12, 10, 20, 15 }; // 价值数组 int W = 5; int[][] result = backPack(w, v, W); for (int i = 0; i < result.length; i++) { for (int j = 0; j < result[0].length; j++) System.out.print(result[i][j] + " "); System.out.println(); } } public static int[][] backPack(int[] w, int[] v, int W) { // w是物品重量数组,v事物品价值数组,W是背包重量 // 返回表达背包问题求解过程的矩阵 int n = w.length; // w和v的长度是相同的 int[][] result = new int[n + 1][W + 1]; // 前i个物品(i从0到n),W从0到W // 初始条件:result[0][j] = 0;result[i][0] = 0; for (int i = 0; i <= W; i++) result[0][i] = 0; for (int i = 0; i <= n; i++) result[i][0] = 0; // 根据动态规划的状态转移方程填表:这个表格可以一行一行的填,也可以一列一列的填,这里采用一行一行的填 // 注意填表方式是动态规划里面非常重要的一个东西,当你填某一个位置时,它需要用到的其他位置必须都已经填好 // 所以填表的方式是跟状态转移方程相关滴,深层次来说,是跟动态规划构造解的生成过程相关的 for (int i = 1; i <= n; i++) // 行数从1到n { for (int j = 1; j <= W; j++) // 列数从1到W { // 此时决定了一个i,j的位置要填:result[i][j] if (j - w[i - 1] < 0) result[i][j] = result[i - 1][j]; else result[i][j] = max(result[i - 1][j], v[i - 1] + result[i - 1][j - w[i - 1]]); } } return result; } public static int max(int m, int n) { if (m >= n) return m; return n; } }
结果:
0 0 0 0 0 0
0 0 12 12 12 12
0 10 12 22 22 22
0 10 12 22 30 32
0 10 15 25 30 37
写了这么几个动态规划,已经可以发现,有了递推式后,其编程就显得非常easy,基本上就是照着公式操作矩阵。
因此,应重点关注动态规划的思想,怎么去描述和刻画问题,发现最有子结构,得到其状态转移方程。
-------------------------------------------------------------------------------------------------------------------------------------------------
2,记忆递归--动态规划的另一种实现方式
关于什么什么是记忆递归,它的出发点是什么,为什么要记忆递归,这些在前面都提过,这里再简单说下:
动态规划的核心思想之一就是记忆(或者记录)来避免对重复子问题进行求解,然而,它并没有避免对不必要子问题进行求解。
若将递归与动态规划结合起来,就可以得到一种动态规划的递归实现方式,这种方式避免了对不必要子问题进行求解。
实际上就是在递归的时候,在动态规划表中先检查要递归的项是否已经求出来了,如果已经求出来了,就直接返回答案,否则才去递归求解。
背包问题的记忆递归实现:
![](http://pic002.cnblogs.com/images/2011/282432/2011070521275858.jpg)
实际上,就是在V[ i , j]还没有求出来的时候(一旦一个V[ i , j]求出来了,就不会再变,这点很重要),才去递归,否则就直接返回值。
想想斐波拉契数列也可以记忆递归的去实现。
-------------------------------------------------------------------------------------------------------------------------------------------------
总结:
1) 背包问题的时间复杂度和空间复杂度都是 nW,2个循环,见代码
2)一个关键点:动态规划的另一种实现方式,记忆递归
相关文章推荐
- rnqoj 拔河问题 一重背包问题(递归求解,dp求解)
- 动态规划6-背包问题+记忆递归
- 记忆搜索与动态规划——DP背包问题
- 动态规划6-背包问题+记忆递归
- 背包问题的递归与非递归求解
- 背包问题---递归及动态规划
- 【日常学习】【背包DP】codevs1014 装箱问题题解
- 背包问题(非递归解法)
- UVA1347-Tour 双调欧几里得旅行商问题 - 递归记忆实现
- HDU 2546 饭卡 【入门DP之01背包问题】
- DP复习——有依赖的背包问题
- 回溯法_0/1背包问题(非递归)
- C++递归问题之三---0-1背包问题:给定两个值value和num,在1到num之间取值使这些数和为value,输出所有组合
- 背包问题(递归)
- HDU 3127 WHUgirls dp背包问题
- 递归-I-背包问题
- 0-1背包问题(递归解决)
- 动态规划:背包问题(DP系列)
- 背包问题 (DP)
- DP背包问题