[dp优化]个人对dp优化的理解

时间:2023-02-09 09:50:57

引言

dp 所要解决的是多阶段决策问题,它利用递归的思想,将规模为n的问题转化为规模较小的问题,直到转化为小到能够直接求解的子问题。通常来说这样做时间复杂度是指数级的,但是如果所有不同的子问题的数目是多项式级别,那么多项式时间就可以解决这个问题,这就是 dp 的本质
dp
(1)
(2)
(3)
O(nt)O(ne)tD/eD
这样可以得到四类典型的动态规划方程
1D/1D:D[0]
E[j]=min { D[i]+w(i,j) } f(j)i<j
2D/0D:D[i][0]D[0][j]
E[i][j]=min { D[i1][j]+xi,D[i][j1]+yi,D[i1][jz]+zi,j }
2D/1D:D[i][i]=0
E[i][j]=w(i,j)+min { C[i,k1]+C[k,j] } i<kj
2D/2D:D[i,0]D[0,j]
E[i][j]=min { D[i][j]+w(i+j,i+j) } 0i<i,0j<j
dpO(ne+t)
dp 优化无外乎状态优化和转移优化两种手段,状态优化往往依赖于具体题目而变,我们主要研究的是转移优化,转移优化常见的手段有:斜率优化,四边形不等式优化和具体数据结构优化等等,还有一类特殊的针对递推线性的优化即矩阵乘法

一些准备知识

移动窗口:单调队列简介

单调队列是应对较为简单的具有单调性的问题的有力手段,而单调队列的使用不外乎下面五个要点
(1)
(2)
(3)ijijjii
(4) :由前面我们知道,队列里的决策时刻满足后面的决策比前面的决策后出现,且更劣
(5) 最优选择在队首:如果后面有一个决策比队首更优,那么它将成为队首,由队列的单调性也可知这一点

动态凸壳:平衡树的应用

前面提到这里的单调性经常与凸包挂钩,而我们时常要维护的是决策点在决策平面上的一个上凸壳或是下凸壳
使(x,y)x

动态凸壳:神器的CDQ分治

在动态凸壳问题中我们还可以用CDQ分治来解决,这里不多赘述了。

1D/1D优化 f[i]=min { f[j]+w(i,j) }

第一种情况:分离决策与状态

这一类优化针对的是这样一类 w(i,j)
w(i,j)=μ(i)+ϕ(j)
也就是说 w(i,j)iμjϕ

(1) f(j)
(2) f(j)线

第二种情况:斜率优化

这一类优化针对的是这样一类方程
f(i)=min { aixj+biyj }

jxj,yj 将每一个决策视作一个点 (xj,yj)
现在我们的决策平面上有很多点,那么我要寻找的是这样一个点使得
P=aix+biy
我们将这个式子变形,有
y=aibi+Pbi
这个式子代表的是一个直线,这个直线过决策点 (x,y) ,且斜率为一个定值,而 P 最优就意味着纵轴截距最优,也就是说,现在我过每一个决策点作一条相同斜率的直线,求纵轴截距最优的那个点
显然这个点只可能存在于所有点的凸壳上(具体是上凸壳还是下凸壳视情况而定),在凸壳上寻找这个点我们只需要二分斜率即可(斜率单调的话直接可以用第一个点或最后一个点),而维护凸壳我们使用平衡树即可(如果横坐标单调就不用这么麻烦了,使用单调队列即可)

第三种情况:决策单调性优化


f(i)=min(f(j)+w(i,j))
w(i,j)
w(i,j+1)w(i,j)>=w(i+1,j+1)w(i+1,j)
w
注:满足这个不等式就意味着w满足四边形不等式,下面会提到

满足这个不等式等价于
k(x)xij,k(i)k(j)

这样,我们可以使用一个栈来维护数据,栈中的每一个元素保存每一个决策是最优的起始位置和终止位置(这显然是一个区间,我们称之为这个决策的作用区间),显然这些区间相互连接且递增
首先我们要寻找最优决策就是要寻找当前状态在哪个决策的作用区间里,由区间的单调性我们二分即可
每次我们还要加入一个新决策,我们从后往前扫描栈,扫到一个老决策的时候,我们做这样两件事:
(1) 如果这个老决策的作用区间的起始位置仍然不如新决策优,那么我们弹出老决策,将老决策的作用区间整个合并到新决策中,继续往前扫
(2) 如果不满足前面的条件,在老决策的作用区间中二分出新决策起作用的起始位置,将老决策分割,新决策入栈,结束扫描过程

2D/1D优化:四边形不等式优化 f(i,j)=w(i,j)+min { f(i,k1)+f(k,j) }

四边形不等式
i<i<j<jw(i,j)+w(i,j)w(i,j)+w(i,j)w
区间包含关系的单调性
i<i<j<jw(i,j)w(i,j)w
【定理1】
wf

我们定义 s(i,j)f(i,j)
【定理2】
s(i,j1)s(i,j)s(i+1,j)

这样转移方程从原来的
f(i,j)=w(i,j)+min { f(i,k1)+f(k,j) } ikj
变成了
f(i,j)=w(i,j)+min { f(i,k1)+f(k,j) } s(i,j1)ks(i+1,j)
复杂度从 O(n3)O(n2)

线性递推优化:矩阵乘法

一般地,对于 m 项递推式,我们记递推式为
fn+m=m1i=0bifn+i

我们就可以把递推式写成如下矩阵形式

an+man+m1an+1

=

bm1100bm2010b1001b0000

×

an+m1an+m2an

然后就可以在 O(m3logn) 时间内解决