线性DP
简单的线性递推
每一项都是由他的前一项递推而来,
例如
当m=2,c1=c2=a1=a2=1时,是斐波那契数列。咱们需要算出第n项,咋算:
使用矩阵快速幂:
对于如下方程,
对于更加复杂的内容,我们可以通过如下操作
最长上升子序列
首先,我们都知道一个n平方的DP做法,我们假设dp[i]
是以a[i]
结尾的最长上升子序列的值,那么我们可以找到递推式,
我们可以进行一系列的优化:
我们主要通过二分来优化。
由于该做法并没有直接算出最终子序列的结果,我们可以通过一个pre数组来指定该字符之前的字符号码。
数字三角形EXT
想必大家都知道数字三角形的原型了。
我们来看几个变形:
+ 将原问题中的使路径和最大改成使路径和模m最大。
做法如下:
+ 增加路径必须经过第r行,第c列这个条件
做法:
1)以(r,c)为头节点做一次DP,以(r,c)为底做一次DP
2)在该位置增加一个极大的权值,最后的答案减去这个数(我们保证DP过程一定会经过该节点)。
背包问题
我已经写了一部分,
还有比较复杂的变种
二维背包
之前咱们的背包只是讨论了一维空间的限制情况,二维背包指的是对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价,对于每种代价都有一个可以付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。
咱们可以多加一个维度的状态便可以实现。
同样咱们可以降维度,使用二维的数组。
分组背包
有N件物品和一个容量为V的背包,第i件物品的费用是c[i],价值是w[i],这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可以是这些物品的费用总和不超过背包容量,且价值总和最大。
咱们设f[k][v]表示前k组物品花费费用用v能取得的最大权值。
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]},其中物品i属于组k
咱们先枚举组,枚举容量,枚举物品。
区间DP
顾名思义,就是在区间上进行动态规划。
就是说,这类问题在进行一次决策之后,决策区间会有一个大区间分成两个小区间,问题也由一个规模较大的问题分解成两个规模较小的问题。
咱们就可以从长度较小的区间向长度较长的区间进行递推。
应用:
通过区间DP,求解回文数
矩阵最右连乘问题
考虑最后一次做乘法的为位置,这会将原问题分解成两个规模较小的子问题,咱们需要枚举最后一次乘法的位置,转移的复杂度是O(n),同时合法的子区间个数存在n平方
总的时间复杂度是n三次方。
+ 括号匹配
1)使用卡塔兰数(出入栈的一种计算总个数的方法)
2)区间DP
石子归并
如果不要求相邻的石子,最小生成树
如果要求:
dp[i][j]=min{dp[i][k]+dp[k+1][j]}+a[i]+......+a[j]
如果石子不是沿着直线排列,而是连成一个环,那怎么办
1)枚举还断开的时间,n4方的时间复杂度
2)将原石子复制一份接在后面,令a[n+i]=a[i],在长度为2n的石子串上做区间DP(对整体做区间DP,但是咱们得出结果是只是dp[i][i+n],i从1到n)
决策单调性与不等式优化
咱们甚至存在石子归并最初问题的n平方的时间复杂度。
这就是四边形不等式优化
树形DP
- 通常动态规划是线性的,一般在有向无环图上进行
- 树形DP是在树这种数据结构上进行的动态规划
- 树形DP有两种方向,自顶向下,自底向上
- 叶->根:在回溯的时候从叶子节点往上更新信息
- 根->叶:往往在从叶子往根dfs之后,在重新往下获得最后的答案。
没有上司的舞会(超级经典)
代码:
树的重心
代码:
树上最远距离
分析:
代码:
感谢B站西北工业大学上传的视频