动态规划,首先问什么是动态规划?这是百度百科的解释,比较详细,时空转移(点击打开链接)。上面的解释虽然详细,但是比较难懂,对于我来说,由于受一些思想的影响,我理解的动规可能并不是一种具体的算法,而是一种思维的过程。为什么这样说呢?其实这是在解决动态规划题目的过程中深深的体会,所以对于每一个人来说,可能对于动规的理解方式都不一样。
其实,也之所以说动态规划难,可能就如同前面说的那样,不容易抓住它的本质、特点,以及它的灵活性、多变性、思维性,这是我们使用它的障碍,却也是它解决问题时所具有的独特的优点。这样一来,要掌握动规不太容易,但也不是完全无迹可寻,下面就来说说方法。
首先,我们需要搞清楚的就是动规的目的,关键词是:最优化,一般动规通常用于求解最优化问题。
其次,我们需要搞清楚的就是动规解决问题的一般思路,关键词是:子问题,就是通过将一个完整问题分为多个相互联系的子问题,然后通过解决子问题从而求出最终的解,但是说到这里,我们不得不提到的是也有另外两种不同的算法使用的时这种思路,它们就是贪心和分治,后面我们会谈谈它们之间的区别。
最后,我们还需要确定什么时候可以使用动规求解问题,可能大家从前两点已经知道了一些端倪,既然要求解最优值,并且又是从子问题求解到整个问题,那必然要求局部的最优解能够推导出全局最优解。下面给出两条能用动态规划求解的问题本身所具有的重要性质:1、最优子结构。2、子问题重叠。最优子结构正如前面分析的那样,而子问题重叠却是动规发挥威力的另一个体现。那么什么又是子问题重叠呢?通俗的的讲,就是当使用一般算法解决问题时,需要将这个问题的多个子问题重复计算多次,这样必然浪费很多时间。那么动规是如何解决这个问题的呢?其实很简单,那就是将已经计算过的子问题保存下来呗!当再次需要某一个子问题的解时,直接拿来用即可,而不用再去重新计算了!
有了上面的这些认识,那么具体如何使用动态规划去解决问题呢?不忙,还有一个关键词需要理解,那就是:状态,我们使用状态来描述当前子问题的情况,那我们如何定义状态呢?这个就是展现能力的时候了,需要具体情况具体分析!自然而然,既然每一个子问题有了描述,那如何去刻画子问题间的关系呢?那就是另一个关键词:状态转移,状态转移代表从一个子问题过度到另一个子问题,实际上这是一个方程,叫做动态转移方程。好了,至此我们便可归纳出设计动态规划算法的一般步骤(注意“设计”一词):
1、将一个问题分解为多个子问题
2、找出合适的状态,既能合理的描述子问题,又能较为方便的计算答案
3、确定子问题之间的关系,推导状态转移方程(一般自底向上转移)
4、综合所有子问题的解,求出整个问题的解
到这里,不知道大家有没有对动规有一个初步的理解,这里再强调一下一些比较重要的关键词,它们在不同的方面深深得影响着算法的设计,因此必须对它们要有一个深刻的理解,即:最优化、子问题、最优子结构、子问题重叠、状态、状态转移。还要强调一点的是:动态规划算法是灵活设计出来的!不是现成的!
哦,对了,前面提了,还要说明一下动规和贪心以及分治之间的关系。
1、动规与贪心
学了贪心,我们知道它和动规一样同样具有最优子结构,但是它们之间一个显著的区别是:贪心在每一个子问题中做决策时,只会考虑在当前看起来是不是最优解,然后没有联系的过度到下一个子问题,而动规在每个状态中求解最优时,需要考虑其它状态的解,这是通过状态转移方程来实现的。通俗的讲就是,贪心处在局部时只考虑局部,动规处在局部时其实考虑的全局。
2、动规与分治
同样的,分治算法也将整体化为局部去求解,但是我们发现当它通过递归去划分整体时,每一次产生的子问题总是新的,也就是说分治不具有重叠子问题的性质,不需要对某一个局部进行反复的求解,这是它与动规的最大区别。
基本概念和思路说完了,下面就要具体的去做练习了,但是动态规划也有很多不同的类型,后面都会一一说到,鉴于最近遇到的概率dp较多,就先从它开始吧。
传送门-概率dp(点击打开链接)。
最近发现状压dp经常穿插在其它的一些算法中考查,so,搞搞它吧。
传送门-状压dp()。