各种DP分类
基本原理
三个条件:
- 最优子结构:能将大问题分解成小问题,并且大问题的最优解能通过小问题的最优解构成。
- 无后效性:已经求解的子问题,不会再受到后续决策的影响。
- 子问题重叠:可以用数组存下重叠的子问题来提升效率。
基本思路:
- 将原问题分解成若干个阶段,找出每个阶段对应的子问题的特征(称为状态)
- 找每个状态可能的决策,即各状态之间的转移方式(称为状态转移方程)
- 找方程的边界,确定转移的顺序。
(可以按顺序递推着写,不好确定顺序时也可以记忆化搜索)
本质上可以对应到图上,状态为节点,决策为边,构成DAG,按拓扑序递推。
线性DP
LIS & LCS
LIS(Longest Increasing Subsequence 最长上升子序列)
计算序列
Sol:
定义
从前往后转移即可(顺序)。
最后
Another Sol:
上面的算法太慢了,考虑优化。
记
下面证明:随着
运用反证法。假设存在
现在来考虑以
由于
又由于
二分出
其他类似问题,最长下降子序列,最长不升子序列,最长不降子序列,考虑的方式是类似的。所以记住LIS的推导即可。
LCS(Longest Common Subsequence 最长公共子序列)
求序列
Sol:
定义
考虑转移:
前两项是继承,第三项是尝试拓展。
边界:
从前往后转移即可。
Another Sol:
上面的算法太慢了,考虑优化。
我们把序列
再将排列中的每个数对应到它的下标,则序列
此时LCS长度不变(这由映射关系是显然的),并且注意到LCS的长度等于序列
于是转到对LIS的优化。
(注意序列
背包
01背包
Sol:
定义
前一项是继承,后一项是尝试做选择第
从前往后转移即可。
代码实现可以压掉第一维,但注意转移顺序,要倒着转移(显然的,看转移方程)。
回退背包
自己起的名字。可能不叫这个。
01背包算好后其中的物品是无序的,可以随便钦定一个物品作为最后一个加入的,然后倒着跑背包撤销这个物品的影响。
注意这个东西只能在信息支持简单撤销时能用,比如加法改成减法,求
完全背包
与01背包类似,但一个物品可以取无限次。
有两种解决方式:
The First Sol:
把每种物品拆成每
The Second Sol:
同01背包定义
注意到与01背包的区别只在于做决策时的下标。
第一维同样可以压掉,但是注意转移顺序,正着转移即可。
多重背包
与01背包类似,但第
Sol:
考虑二进制分组,每
可以证明这样可以组合出每一种决策。
然后转化为01背包做。
混合背包
01背包、完全背包、多重背包混在一起。
Sol:
分类讨论一下,把三种代码拼在一起。
或者都用二进制分组。
二维(多维)费用背包
在背包物品要消耗体积外还有其他费用(比如重量、时间等)。
Sol:
多开几维,同样可以把枚举第
分组背包
与01背包类似,但是每组内的物品只能选一个。
Sol:
每组之内做一次01背包。
具体而言,定义
每一组内枚举其中的物品尝试转移。
更一般的线性DP
难点在于消除可能的后效性。
在线性DP中我们通过观察题目性质和优化状态设计来做到这一点。
有时会设计出形如
区间DP
区间DP其实是特殊的线性DP,以区间长度为阶段。
基本思想是从小区间转移到大区间。
一般很板,就是从小到大枚举区间,然后枚举断点转移。
状态一般设为
有二维的形式,也类似,状态设为
处理环
一般断环成链,将原数组复制一份接在后面即可。
转移涉及当前区间最值
可以看做是在笛卡尔树的结构上进行DP。
状压DP
本质是将一种状态压缩为一个数进行DP,除此之外与其他DP类似。
注意可以预处理出所有可行状态以提高运行效率。有时这样复杂度才正确。
高级的状压:插头DP。
树形DP
一般的树形DP
只是将DP的操作放到树上,利用树很好的递归性质求解。
一般定义状态为
尝试从
树上背包
就是把背包放到树上。
定义状态为
转移:
注意边界,手推一下。
第二维可以压掉,但要倒序枚举
树上换根
也叫二次扫描,通常要两次DFS。第一次进行一些预处理,第二次开始DP
转移时可以考虑从父亲转移到儿子(因为一般以
关注换根时答案的变化量。
数位DP
问题特征
-
目的是统计满足某种限制的数的个数。
-
限制是针对数位的。
-
提供统计的区间或上界。
-
上界很大,但只看数位个数可以接受。
基本原理
有一个通用答案数组,其中记录在计数过程中大量重复出现的过程的答案(如统计
这个通用答案数组根据题目限制进行DP
区间的询问通常拆成两个区间相减。
统计答案部分可以记忆化搜索,也可以递推。从高到低枚举每一位,注意贴上限时的处理(如上限为
部分套路:
第
定义状态为
根据题意尝试转移。
还可以尝试继续压缩常数,参数里面能相互推的压在一起。
记忆化搜索
记搜大法吼!
记搜长得很板,方便拓展。
一般先将边界数字拆到数位上,然后从高位到低位填数。用个数组记忆化一下。
一般有以下形参:
-
:当前枚举到的位置。 -
:第 位是否受限(前几位是否贴上界)。初始时可以理解为前面都贴了 的上界。 -
:第 位前面是否有前导零。前导零与答案有关时才记,零只有在不是前导零时才算贡献。
接着是根据题意得到的限制条件,记搜时要作为状态的一部分塞到形参里以及状态里。
考虑用于记忆化的数组!lim&&!lead
(没有限制)才能返回
计数DP
特征:计算满足限制的方案总数。
注意计数时要求的不重不漏。有重复时考虑容斥减掉或者设计一种DP顺序使方案不重复。
一般是数学推式子再套上DP
概率期望DP
就是概率期望相关的数学推式子套上DP
一些套路:
对于概率DP,一般是正着DP,即定义状态
对于期望DP,一般是倒着DP,即定义状态
插头DP
连通性相关的状压DP。
适用于各种网格覆盖相关且允许状压的问题。
SOS DP
Sum Over Subset DP,子集和DP。是特殊情况的高维前缀和。
每一维只是
表述更为清晰一点的例子是,求
复杂度与值域有关,设值域为
现在来讲做法,设
那么就有分讨了:
-
的第 位为 ,那么必须选 , 加上 。 -
的第 位为 ,则 加上
这样就不重不漏地数完了。
超集和DP也是类似的,分讨一下就做完了。
和数位DP有一定相似性,但侧重点不同。数位DP擅长处理一段连续区间中的数数问题,而SOS DP擅长处理不那么连续,而是较为离散的点的数数问题,而且点的权值可以任意给,缺点是复杂度太高。
有后效性的DP的处理方法
一般是按某个值排序(如DP值,而且不是真的排序,只是规定了顺序)。
然后可以按照类似跑最短路的方式转移。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!