您的位置:首页 > 其它

练习3——动态规划总结

2016-05-18 22:40 302 查看
    动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解 题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。

 

    动态规划问题运算量比较大,通常提前列出问题的所有可能并保存到表中,在根据键值查表,这种方法的特点是牺牲空间来换取时间,举个简单的例子,斐波拉契数列,求f(10),需要11次运算,求f(11),需要12次运算,如果用公式f(n) = f(n-1) + f(n-2)分开求,需要计算11+12=23次,但如果将将f(10)保存,计算f(11),只需在f(10)的基础上再运算一次,即11+1=12次。可见,这种做法非常节省时间。

 

    在本套专题中遇到的DP问题类型:类斐波那契数列问题,01背包(以1019,1017题为例),完全背包(以1022题为例),最长升序子序列问题,最大公共子序列(以1002题为例)问题。

 

    类斐波那契数列问题,指特征方程类似于 f(n) = f(n-1) + f(n-2),的问题,此类问题最直观的题就是斐波那契数列,稍微难一点的就是跳楼问题,和堆砖头问题,这两个题虽然看起来与斐波那契没什么关系,但是经过分析和转化之后,就可以转化为该类型。总的来说,类斐波那契数列问题是这套专题里最简单的问题,只要做会了几个典型,其他的就很简单了。

 

    01背包,一般描述为给定背包的容积,一些物品的价值和体积,求能放入背包中的物品的最大价值,一个比较通用的公式为f[i, j] = max( f[i-1, j-Wi] + Pi (j >=Wi), f[i-1, j] ),这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f
是一种恰好装满背包的最优解。如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。

 

    完全背包,这个问题非常类似于01背包问题,所不同的是每种物品有无限件,也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……取[V/c]件等很多种。

 

    最大公共子序列,又称LCS,由于上课老师没有讲过,便自己学习了一下,这类问题一般描述为给定一定个字符串,求出个个串最长的公共子序列的长度,这种问题的解决思路很巧妙,用一个矩阵,行和列每个格子代表一个字符,分别表示出两个字符串,如图,引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i]
= Y[j]还是X[i] != Y[j],就可以计算出c[i][j],即问题的解。



 

感想: 动态规划问题,相较于贪心和搜索来说,一个显著的特点就是代码量很少,一个贪心或者搜索问题,一般都会有五六十行代码,而一个DP问题的代码量,往往就十几行甚至更短,以至于真正的核心就那么一行递推公式。但这并不代表DP问题就简单,做DP问题需要很强的逻辑思维和思考能力(思路很重要,思路好的时候,一天可以AC 5道题,要是思路不好,一天可能一道题也做不出来),需要一颗具备把逻辑问题转化为特征方程能力的大脑,总之,做DP问题,是真正用“脑子”做题,不是像搜索一样,靠“模板”来嵌套。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息