动态规划6-背包问题+记忆递归
2014-12-22 16:59
357 查看
转自:http://blog.csdn.net/mengzhejin/article/details/37880857
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,可以得到下列递推式:
这个递推式的意思是:如果 i 的重量已经比 j 大了,那显然不含 i ( j-wi < 0 ), 如果 i 的重量比 j 小,那么可能包含 i (如果包含能去到最大值的话)。
这个表可以按行也可以按列填:
实现:
结果:
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,记忆递归--动态规划的另一种实现方式
关于什么什么是记忆递归,它的出发点是什么,为什么要记忆递归,这些在前面都提过,这里再简单说下:
动态规划的核心思想之一就是记忆(或者记录)来避免对重复子问题进行求解,然而,它并没有避免对不必要子问题进行求解。
若将递归与动态规划结合起来,就可以得到一种动态规划的递归实现方式,这种方式避免了对不必要子问题进行求解。
实际上就是在递归的时候,在动态规划表中先检查要递归的项是否已经求出来了,如果已经求出来了,就直接返回答案,否则才去递归求解。
背包问题的记忆递归实现:
实际上,就是在V[ i , j]还没有求出来的时候(一旦一个V[ i , j]求出来了,就不会再变,这点很重要),才去递归,否则就直接返回值。
想想斐波拉契数列也可以记忆递归的去实现。
-------------------------------------------------------------------------------------------------------------------------------------------------
总结:
1) 背包问题的时间复杂度和空间复杂度都是 nW,2个循环,见代码
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,可以得到下列递推式:
这个递推式的意思是:如果 i 的重量已经比 j 大了,那显然不含 i ( j-wi < 0 ), 如果 i 的重量比 j 小,那么可能包含 i (如果包含能去到最大值的话)。
这个表可以按行也可以按列填:
实现:
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,记忆递归--动态规划的另一种实现方式
关于什么什么是记忆递归,它的出发点是什么,为什么要记忆递归,这些在前面都提过,这里再简单说下:
动态规划的核心思想之一就是记忆(或者记录)来避免对重复子问题进行求解,然而,它并没有避免对不必要子问题进行求解。
若将递归与动态规划结合起来,就可以得到一种动态规划的递归实现方式,这种方式避免了对不必要子问题进行求解。
实际上就是在递归的时候,在动态规划表中先检查要递归的项是否已经求出来了,如果已经求出来了,就直接返回答案,否则才去递归求解。
背包问题的记忆递归实现:
实际上,就是在V[ i , j]还没有求出来的时候(一旦一个V[ i , j]求出来了,就不会再变,这点很重要),才去递归,否则就直接返回值。
想想斐波拉契数列也可以记忆递归的去实现。
-------------------------------------------------------------------------------------------------------------------------------------------------
总结:
1) 背包问题的时间复杂度和空间复杂度都是 nW,2个循环,见代码
2)一个关键点:动态规划的另一种实现方式,记忆递归
相关文章推荐
- 动态规划:0-1背包问题(使用递归方法)
- 动态规划在求解背包问题中的应用(JAVA)--回溯法、记忆化法
- 背包问题---递归及动态规划
- 背包问题---递归及动态规划
- 0/1背包问题动态规划详解
- 01背包问题动态规划详解(转载)
- 动态规划_背包问题扩展
- 动态规划解背包问题/C++/Knapsack problem
- 01背包问题动态规划详解
- 0-1背包问题;动态规划;时间复杂度O(n方);给出最大价值与解得情况;内有动态规划思路总结;
- 0-1背包问题动态规划
- 0-1背包问题的动态规划解法
- DP之背包问题+记忆递归
- 动态规划解决0-1背包问题
- 0/1背包问题动态规划详解
- 动态规划——背包问题变形
- 01背包问题动态规划详解(转载)
- 0/1背包问题动态规划详解
- 0/1背包问题动态规划详解(转)
- 动态规划——背包问题变形 收藏