四边形不等式优化 区间类(2D1D)动态规划中的应用 在区间类动态规划(如石子合并问题)中,我们经常遇到以下形式的 2D1D 状态转移方程:
直接简单实现状态转移,总时间复杂度将会达到 
区间包含单调性 :如果对于任意 四边形不等式 :如果对于任意 四边形恒等式 。引理 1 :若 
定义 
注意到,仅当 
首先注意到若 
考虑对区间长度 
 若 
 若 
 
 若 
 再由 
 将前两个不等式累加,并将第三个不等式代入,可得
 若 
 再由 
 将前两个不等式累加,并将第三个不等式代入,可得
 综上所述,两种情形均有 
定理 1 :若状态 
记 
若 
 再根据 
 将以上两个不等式相加,得
 即 
若 
 再根据 
 将以上两个不等式相加,得
 即 
因此,如果在计算状态 
核心代码  // C++ Version 
for   ( int   len   =   2 ;   len   <=   n ;   ++ len )    // 枚举区间长度 
   for   ( int   l   =   1 ,   r   =   len ;   r   <=   n ;   ++ l ,   ++ r )   {      // 枚举长度为len的所有区间 
     f [ l ][ r ]   =   INF ;      for   ( int   k   =   m [ l ][ r   -   1 ];   k   <=   m [ l   +   1 ][ r ];   ++ k )        if   ( f [ l ][ r ]   >   f [ l ][ k ]   +   f [ k   +   1 ][ r ]   +   w ( l ,   r ))   {          f [ l ][ r ]   =   f [ l ][ k ]   +   f [ k   +   1 ][ r ]   +   w ( l ,   r );    // 更新状态值 
         m [ l ][ r ]   =   k ;    // 更新(最小)最优决策点 
       }    } 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 # Python Version 
for  len  in  range ( 2 ,  n  +  1 ):  # 枚举区间长度 
    r  =  len 
    l  =  1 
    while ( r  <=  n ): 
        # 枚举长度为len的所有区间 
        r  +=  1 
        l  +=  1 
        f [ l ][ r ]  =  INF 
        k  =  m [ l ][ r  -  1 ] 
        while  k  <=  m [ l  +  1 ][ r ]: 
            if  f [ l ][ r ]  >  f [ l ][ k ]  +  f [ k  +  1 ][ r ]  +  w ( l ,  r ): 
                f [ l ][ r ]  =  f [ l ][ k ]  +  f [ k  +  1 ][ r ]  +  w ( l ,  r )  # 更新状态值 
                m [ l ][ r ]  =  k  # 更新(最小)最优决策点 
            k  +=  1 
基于分治的决策单调性优化 某些 dp 问题形式如下:
总共有 
实际上此形式也有同样的结论,可以在 
令 
我们可以更有效地解出所有状态。假设我们对于固定的 
为了最小化运行时间,我们便需要应用分治法背后的思想。首先计算 
参考代码   1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 int   n ; long   long   C ( int   i ,   int   j ); vector < long   long >   dp_before ( n ),   dp_cur ( n ); // compute dp_cur[l], ... dp_cur[r] (inclusive) 
void   compute ( int   l ,   int   r ,   int   optl ,   int   optr )   {    if   ( l   >   r )   return ;    int   mid   =   ( l   +   r )   >>   1 ;    pair < long   long ,   int >   best   =   { INF ,   -1 };    for   ( int   k   =   optl ;   k   <=   min ( mid ,   optr );   k ++ )   {      best   =   min ( best ,   { dp_before [ k ]   +   C ( k ,   mid ),   k });    }    dp_cur [ mid ]   =   best . first ;    int   opt   =   best . second ;    compute ( l ,   mid   -   1 ,   optl ,   opt );    compute ( mid   +   1 ,   r ,   opt ,   optr ); } 
1D1D 动态规划中的应用 除了经典的石子合并问题外,四边形不等式的性质在一类 1D1D 动态规划中也能得出决策单调性,从而优化状态转移的复杂度。考虑以下状态转移方程:
定理 2 :若函数 
记 
又由于 
将以上两个不等式相加,可得
即 
但与 2D1D 动态规划中的情形不同,在这里我们根据决策单调性只能得出每次枚举 
先考虑一种简单的情况,转移函数的值在动态规划前就已完全确定。即如下所示状态转移方程:
在这种情况下,我们定义过程 
代码实现  // C++ Version 
void   DP ( int   l ,   int   r ,   int   k_l ,   int   k_r )   {    int   mid   =   ( l   +   r )   /   2 ,   k   =   k_l ;    // 求状态f[mid]的最优决策点 
   for   ( int   i   =   k_l ;   i   <=   min ( k_r ,   mid   -   1 );   ++ i )      if   ( w ( i ,   mid )   <   w ( k ,   mid ))   k   =   i ;    f [ mid ]   =   w ( k ,   mid );    // 根据决策单调性得出左右两部分的决策区间,递归处理 
   if   ( l   <   mid )   DP ( l ,   mid   -   1 ,   k_l ,   k );    if   ( r   >   mid )   DP ( mid   +   1 ,   r ,   k ,   k_r ); } 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 # Python Version 
def  DP ( l ,  r ,  k_l ,  k_r ): 
    mid  =  int (( l  +  r )  /  2 ) 
    k  =  k_l 
    # 求状态f[mid]的最优决策点 
    for  i  in  range ( k_l ,  min ( k_r ,  mid  -  1 )): 
        if  w ( i ,  mid )  <  w ( k ,  mid ): 
            k  =  i 
    f [ mid ]  =  w ( k ,  mid ) 
    # 根据决策单调性得出左右两部分的决策区间,递归处理 
    if  l  <  mid : 
        DP ( l ,  mid  -  1 ,  k_l ,  k ) 
    if  r  >  mid : 
        DP ( mid  +  1 ,  r ,  k ,  k_r ) 
使用递归树的方法,容易分析出该分治算法的复杂度为 
题目大意  给定一个长度为 
 显然,经过不等式变形,我们可以得到待求整数 
根据 
现在处理一般情况,即转移函数的值是在动态规划的过程中按照一定的拓扑序逐步确定的。此时我们需要改变思维方式,由“确定一个状态的最优决策”转化为“确定一个决策是哪些状态的最优决策“。具体可见上文的「单调栈优化 DP」。
满足四边形不等式的函数类 为了更方便地证明一个函数满足四边形不等式,我们有以下几条性质:
性质 1 :若函数 
性质 2 :若存在函数 
性质 3 :设 
性质 4 :设 
首先需要澄清一点,凸函数(Convex Function)的定义在国内教材中有分歧,此处的凸函数指的是(可微的)下凸函数,即一阶导数单调增加的函数。
前两条性质根据定义很容易证明,下面证明第三条性质,性质四的证明过程类似。
任取 
任取 
移项,并根据 
记 
设 
即 
回顾例题 1 中的 
题目大意  有 
设 
记 
习题 参考资料 本页面主要译自英文版博文 Divide and Conquer DP 。版权协议为 CC-BY-SA 4.0。 
build 本页面最近更新:2022/4/20 20:21:30 ,更新历史 edit 发现错误?想一起完善? 在 GitHub 上编辑此页! people 本页面贡献者:StudyingFather , Ir1d , billchenchina , Chrogeek , Elitedj , Enter-tainer , fps5283 , greyqz , Henry-ZHR , hsfzLZH1 , iamtwz , izlyforever , ksyx , Marcythm , MingqiHuang , nanmenyangde , opsiff , ouuan , ranwen , sshwy , TrisolarisHD , Xeonacid , yizr-cnyali , zyf0726 , zyj-111 copyright 本页面的全部内容在 CC BY-SA 4.0  和 SATA