动态规划
动态规划一般是来解决
1:计数问题
如有多少种方式走到右下角?
如有多少种方法选出k个数使得和是sum
2:求最大值,最小值
如从左上角走到右下角路径的最大数字和
如最长上升子序列长度
3:求存在性
如取石子游戏,先手是否必胜
如能不能选出k个数使得和是sum
归类成两种类型:
1:优化问题希望你选择一个可行的解决方案,以便最小化或最大化所需函数的值。
2:组合问题希望你弄清楚做某事方案的数量或某些事件发生的概率。
解决方案的对比:自上而下或者自下而上
以下是两种不同的动态规划解决方案:
自上而下:你从最顶端开始不断地分解问题,直到你看到问题已经分解到最小并已得到解决,之后只用返回保存的答案即可。
自下而上:你可以直接开始解决较小的子问题,从而获得最好的解决方案。在此过程中,你需要保证在解决问题之前先解决子问题。表格填充
至于迭代和递归与这两种方法的关系,自下而上用到了迭代技术,而自上而下则用到了递归技术。
取决于该问题是否能用动态规划解决的是这些”小问题“会不会被被重复调用。
经典模型
1.线性模型
最经典的问题就是斐波那楔数列的问题,每个数的值都是一个状态,可以用F[i]表示表示第i个数的值是多少。每个数都是由F[i-1]+F[i-2]转移而来。
另外一个经典的问题就是最长上升自序列(LIS),有一串序列,要求找出它的一串子序列,这串子序列可以不连续,但必须满足它是严格的单调递増的且为最长的。把这个长度输出。示例:1 7 3 5 9 4 8 结果为4。
我们非常容易表示他的状态,我们用f[i]表示以第i个数结尾的,最大的上升自序列是多少?那么它是怎么转移的呢?非常容易想到肯定是从左边的的数转移而来,能转移的数满足什么条件呢?肯定是比a[i]更小的。
线性模式还可以拓展成二维问题,例如背包问题,用f[i][j]表示前i个物品,凑成大小为j的背包,最大的价值是多少。
这类问题非常的多,但是思路都是这样,无非就是从左往右,从上到下,从低维到高维进行转移。
2.区间模型
对于每个问题,都是由子区间推导过来的,我们称之为区间模型,下面是一个例子。
我们有一个连续的序列,每个序列上面都是一个数字c[i],每次我们都能够消灭一个连续的回文子序列,消灭之后左右会合并,成为一个新序列,问最少需要多少次才能够把整个序列消灭掉。回文就是从左到有从右到左读到的序列都是一样的。题目比较抽象,我们通过一些例子来说明这个问题吧?例如一开始的序列是1 4 4 2 3 2 1,那么我们最少需要2次,先消灭掉4 4 , 然后再消灭调1 2 3 2 1.第二个例子是 1 2 3 4 5 5 3 1,我们先消灭掉2 然后再消灭掉4, 最后消灭 1 3 5 5 3 1, 需要3次。
我们经常用f[i][j]来表示消灭i,j区间需要的代价,文末有链接详细叙述这个问题,大家感兴趣的可以看一看。
3.树状模型
我们在数据结构树上面进行最求最优解、最大值等问题,上述我们讲的这个绩效考核就是一个树状模型,具体不再累叙。
动态规划怎么用(四部曲):
1.确定状态(两个核心:1最后一步 2化成子问题)
2转移方程
3开始和边界条件
4计算顺序
a. 找出最优解的性质,并刻划其结构特征。
b. 递归地定义最优值。
c. 以自底向上的方式计算出最优值。
d. 根据计算最优值时得到的信息,构造最优解