从今天起,cgg会给大家讲一讲动态规划。我很菜,所以这系列文章如果能在你感到迷惑的时候,给你一点你认为比较有帮助的提示,我也就满足了。
好,下面我们步入正题,我们就从最基础的看起。
我第一次听到这个高大上的名词时,我有种不明觉厉的感觉,并且听得迷迷糊糊,勉强明白是个啥玩意儿。
当时的我就感觉这个东西好厉害,但是不怎么会用。
我真正地会用大概是在我后来自己自学的时候才明白的。那么,究竟什么是动态规划呢?
它并不是一个算法,而是一种解决问题的方法或者说是思想。
我们来看一个简单的例子。
数字三角形?
不不不,我才不举这个老土的例子,虽然它是个好例子。
我们来看扑克牌,加入我们手上有这样几张牌:
- 一张小王
- 一张A
- 一张K
- 一张Q
- 两张J
- 一张10
我们的问题是最少几次能将我们的牌走完,不考虑他人怎么出牌。
我们也许可以采用枚举,比如我们可以先出一张10,再出两张J;还可以先出两张J,再出一张10.
有什么问题?我们的这两种走法得到的剩下的牌是一样的,也就是说接下来我们需要的是剩下的牌需要多少次才能走完,但是很明显,我们在枚举的时候,就会把这一样的情况枚举两遍,这还算少的,如果我们再加上一张Q进行讨论呢?
那么很明显,计算重复问题的时间就是被浪费的时间,这也是拖慢我们程序速度的问题所在。
那么我们应该怎么去做呢?
我们可以用一些特定的方式去描述每一种可能出现的手牌情况,然后建立一个数组去保存每一种情况下的最优解,这样的话,再次求到同样的问题,我们可以直接把保存的最优解返回。
这就是动态规划的一个应用。
那么 我们什么时候能用动态规划呢?
首先这个问题必须有最优子结构。
什么是最优子结构?
其实很好理解,最优子结构就是指,对于一个最优策略,其子策略也一定是采取当前策略下的最优策略。
有点绕?
换句话说吧,对于扑克牌问题,假如最优策略的第一步是走一张10(虽然这显然不是最优的,我们只是假设),那么对于剩下的牌的走法,我们的最优策略所包括的一定是所有走法里最优的,如果不是,那么我们当前的最优策略就不是最优策略。
除了最优子结构,我们的问题还需要具有无后效性。
什么又是无后效性?
这个更好解释。
就是对于同一个状态,无论它的前一个状态是怎样的,都不会影响到当前的决策。
更直白地说,就是我们对于一种状态的决策只与当前的状态相关。
比如扑克牌问题,我们无论前面怎么走,只要我们剩下的手牌是一样的,那么解决眼前问题的方法与我们以前是怎样出牌的并没有关系。
最后我们还需要子问题重叠性。
这是我们是使用动态规划的原因,正是需要重复计算子问题,我们才想到用动态规划去解决问题。
所以说,如果一个问题没有重叠的子问题,那么我们完全没有必要去使用动态规划。
这就是使用动态规划的条件!
今天就讲到这吧,自己简单消化一下。