四边形不等式优化 四边形不等式优化利用的是状态转移方程中的决策单调性。
基础知识 考虑最简单的情形,我们要解决如下一系列最优化问题。
𝑓 ( 𝑖 ) = m i n 1 ≤ 𝑗 ≤ 𝑖 𝑤 ( 𝑗 , 𝑖 ) ( 1 ≤ 𝑖 ≤ 𝑛 ) ( 1 ) (1) f ( i ) = min 1 ≤ j ≤ i w ( j , i ) ( 1 ≤ i ≤ n ) 这里假定成本函数 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) 𝑂 ( 1 ) O ( 1 ) 
约定  动态规划的状态转移方程经常可以写作一系列最优化问题的形式。以(1)式为例,这些问题含有参数 𝑖 i 𝑖 i 𝑖 i 𝑗 j 𝑖 i 𝑖 i 𝑗 j 𝑗 j 𝑓 ( 𝑖 ) f ( i ) 𝑖 i o p t  ( 𝑖 ) opt  ( i ) 
在一般的情形下,这些问题总时间复杂度为 𝑂 ( 𝑛 2 ) O ( n 2 ) 𝑖 i 𝑗 j 
决策单调性 :对于任意 𝑖 1   < 𝑖 2 i 1 < i 2 o p t  ( 𝑖 1 )   ≤ o p t  ( 𝑖 2 ) opt  ( i 1 ) ≤ opt  ( i 2 ) 附注  对于问题 𝑖 i 𝐴 A 𝐵 B 𝐴   ≤ 𝐵 A ≤ B 𝑎   ∈ 𝐴 a ∈ A 𝑏   ∈ 𝐵 b ∈ B m i n { 𝑎 , 𝑏 }   ∈ 𝐴 min { a , b } ∈ A m a x { 𝑎 , 𝑏 }   ∈ 𝐵 max { a , b } ∈ B 𝑖 1   < 𝑖 2 i 1 < i 2 o p t m a x  ( 𝑖 1 )   > o p t m i n  ( 𝑖 2 ) optmax  ( i 1 ) > optmin  ( i 2 ) 
 另一方面,拥有相同最小最优决策的问题构成一个区间。这一区间,作为最小最优决策的函数,应严格递增。亦即,给定 𝑗 1   = o p t  ( 𝑖 1 ) j 1 = opt  ( i 1 ) 𝑗 2   = o p t  ( 𝑖 2 ) j 2 = opt  ( i 2 ) 𝑗 1   < 𝑗 2 j 1 < j 2 𝑖 1   < 𝑖 2 i 1 < i 2 𝑗 1   < 𝑗 2 j 1 < j 2 [ 𝑙 𝑗 1 , 𝑟 𝑗 1 ] [ l j 1 , r j 1 ] [ 𝑙 𝑗 2 , 𝑟 𝑗 2 ] [ l j 2 , r j 2 ] 𝑟 𝑗 1   < 𝑙 𝑗 2 r j 1 < l j 2 
最常见的判断决策单调性的方法是通过四边形不等式(quadrangle inequality)。
四边形不等式 :如果对于任意 𝑎   ≤ 𝑏   ≤ 𝑐   ≤ 𝑑 a ≤ b ≤ c ≤ d 𝑤 ( 𝑎 , 𝑐 ) + 𝑤 ( 𝑏 , 𝑑 ) ≤ 𝑤 ( 𝑎 , 𝑑 ) + 𝑤 ( 𝑏 , 𝑐 ) , w ( a , c ) + w ( b , d ) ≤ w ( a , d ) + w ( b , c ) , 则称函数 𝑤 w 𝑤 w 四边形恒等式 。
如果没有特别说明,以下都会保证 𝑎   ≤ 𝑏   ≤ 𝑐   ≤ 𝑑 a ≤ b ≤ c ≤ d 
定理 1  若 𝑤 w 
证明  要证明这一点,可采用反证法。假设对某些 𝑐   < 𝑑 c < d 𝑎   = o p t  ( 𝑑 )   < o p t  ( 𝑐 )   = 𝑏 a = opt  ( d ) < opt  ( c ) = b 𝑎   < 𝑏   ≤ 𝑐   < 𝑑 a < b ≤ c < d 𝑤 ( 𝑎 , 𝑑 )   ≤ 𝑤 ( 𝑏 , 𝑑 ) w ( a , d ) ≤ w ( b , d ) 𝑤 ( 𝑏 , 𝑐 )   < 𝑤 ( 𝑎 , 𝑐 ) w ( b , c ) < w ( a , c ) 𝑤 ( 𝑎 , 𝑑 )   − 𝑤 ( 𝑏 , 𝑑 )   ≤ 0   < 𝑤 ( 𝑎 , 𝑐 )   − 𝑤 ( 𝑏 , 𝑐 ) w ( a , d ) − w ( b , d ) ≤ 0 < w ( a , c ) − w ( b , c ) 
四边形不等式可以理解在合理的定义域内,𝑤 w Δ 𝑖 Δ 𝑗 𝑤 ( 𝑗 , 𝑖 ) Δ i Δ j w ( j , i ) 
利用决策单调性,有两种常见算法可以将算法复杂度优化到 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 
分治 要求解所有状态,只需要求解所有最优决策点。为了对所有 1   ≤ 𝑖   ≤ 𝑛 1 ≤ i ≤ n o p t  ( 𝑖 ) opt  ( i ) o p t  ( 𝑛 / 2 ) opt  ( n / 2 ) 1   ≤ 𝑖   < 𝑛 / 2 1 ≤ i < n / 2 𝑛 / 2   < 𝑖   ≤ 𝑛 n / 2 < i ≤ n o p t  ( 𝑖 ) opt  ( i ) o p t  ( 𝑖 ) opt  ( i ) 1 1 o p t  ( 𝑛 / 2 ) opt  ( n / 2 ) o p t  ( 𝑖 ) opt  ( i ) o p t  ( 𝑛 / 2 ) opt  ( n / 2 ) o p t  ( 𝑛 ) opt  ( n ) 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 𝑂 ( l o g  𝑛 ) O ( log  n ) 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 
核心代码  C++ Python 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 int   w ( int   j ,   int   i ); 
void   DP ( int   l ,   int   r ,   int   k_l ,   int   k_r )   { 
   int   mid   =   ( l   +   r )   /   2 ,   k   =   k_l ; 
   // 求状态f[mid]的最优决策点 
   for   ( int   j   =   k_l ;   j   <=   min ( k_r ,   mid   -   1 );   ++ j ) 
     if   ( w ( j ,   mid )   <   w ( k ,   mid ))   k   =   j ; 
   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 ); 
} 
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 ) 
二分队列 注意到对于每个决策点 𝑗 j 𝑖 i 
核心代码  C++ 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 int   val ( int   j ,   int   i ); 
int   lt [ N ],   rt [ N ],   f [ N ]; 
deque < int >   dq ; 
// 顺次考虑所有问题和决策,下标从 1 开始 
for   ( int   j   =   1 ;   j   <=   n ;   ++ j )   { 
   // 出队 
   if   ( ! dq . empty ()   &&   rt [ dq . front ()]   <   j )   dq . pop_front (); 
   if   ( ! dq . empty ())   lt [ dq . front ()]   =   j ; 
   // 入队 
   while   ( ! dq . empty ()   &&   val ( j ,   lt [ dq . back ()])   <   val ( dq . back (),   lt [ dq . back ()]))   { 
     dq . pop_back (); 
   } 
   if   ( dq . empty ())   { 
     lt [ j ]   =   j ; 
     rt [ j ]   =   n ; 
     dq . emplace_back ( j ); 
   }   else   if   ( val ( j ,   rt [ dq . back ()])   >=   val ( dq . back (),   rt [ dq . back ()]))   { 
     if   ( rt [ dq . back ()]   <   n )   { 
       lt [ j ]   =   rt [ dq . back ()]   +   1 ; 
       rt [ j ]   =   n ; 
       dq . emplace_back ( j ); 
     } 
   }   else   { 
     int   ll   =   lt [ dq . back ()],   rr   =   rt [ dq . back ()],   i   =   rr ; 
     // 二分 
     while   ( ll   <=   rr )   { 
       int   mm   =   ( ll   +   rr )   /   2 ; 
       if   ( val ( j ,   mm )   <   val ( dq . back (),   mm ))   { 
         i   =   mm ; 
         rr   =   mm   -   1 ; 
       }   else   { 
         ll   =   mm   +   1 ; 
       } 
     } 
     rt [ dq . back ()]   =   i   -   1 ; 
     lt [ j ]   =   i ; 
     rt [ j ]   =   n ; 
     dq . emplace_back ( j ); 
   } 
   // 计算 
   f [ j ]   =   val ( dq . front (),   j ); 
} 
掌握这一算法,需要理解如下要点:
队列需要记录到目前为止每个可行的决策点 𝑗 j 𝑙 𝑗 l j 𝑟 𝑗 r j 三元组 。对于给定区间 [ 𝑙 𝑗 , 𝑟 𝑗 ] [ l j , r j ] 𝑗 j [ 𝑗 , 𝑛 ] [ j , n ]  初始时,队列是空的。类似于单调队列,每次考虑下一个决策 𝑗 j  出队 :首先将上一个问题 𝑗   − 1 j − 1 𝑗   − 1 j − 1 𝑗 j 入队 :要对决策 𝑗 j 𝑗 ′ j ′ 如果对于问题 𝑙 𝑗 ′ l j ′ 𝑗 j 𝑗 ′ j ′ 𝑤 ( 𝑗 , 𝑙 𝑗 ′ )   < 𝑤 ( 𝑗 ′ , 𝑙 𝑗 ′ ) w ( j , l j ′ ) < w ( j ′ , l j ′ ) 𝑗 ′ j ′ 𝑗 ′ j ′ 𝑗 j 𝑙 𝑗 ′ l j ′  如果队列已空,入队 ( 𝑗 , 𝑗 , 𝑛 ) ( j , j , n ) 𝑗 j  如果队尾决策 𝑗 ′ j ′ 𝑟 𝑗 ′ r j ′ 𝑗 j 𝑟 𝑗 ′   < 𝑛 r j ′ < n ( 𝑗 , 𝑟 𝑗 ′   + 1 , 𝑛 ) ( j , r j ′ + 1 , n ) 𝑗 j [ 𝑟 𝑗 ′   + 1 , 𝑛 ] [ r j ′ + 1 , n ] 𝑗 j  最后的情形是,队尾决策 𝑗 ′ j ′ 𝑗 j 𝑙 𝑗 ′ l j ′ 𝑟 𝑗 ′ r j ′ 𝑖   ∈ ( 𝑙 𝑗 ′ , 𝑟 𝑗 ′ ] i ∈ ( l j ′ , r j ′ ] [ 𝑙 𝑗 ′ , 𝑖   − 1 ] [ l j ′ , i − 1 ] 𝑗 ′ j ′ [ 𝑖 , 𝑟 𝑗 ′ ] [ i , r j ′ ] 𝑗 j 二分  找到最小的 𝑖   ∈ [ 𝑙 𝑗 ′ , 𝑟 𝑗 ′ ] i ∈ [ l j ′ , r j ′ ] 𝑤 ( 𝑗 , 𝑖 )   < 𝑤 ( 𝑗 ′ , 𝑖 ) w ( j , i ) < w ( j ′ , i ) 𝑟 𝑗 ′ r j ′ 𝑖   − 1 i − 1 ( 𝑗 , 𝑖 , 𝑛 ) ( j , i , n )  处理完决策 𝑗 j 𝑗 j 𝑗 j  类似于单调队列,每个决策点至多入队一次,出队一次。这里,出队是 𝑂 ( 1 ) O ( 1 ) 𝑂 ( l o g  𝑛 ) O ( log  n ) 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 
例题 1:「POI2011」Lightning Conductor   给定一个长度为 𝑛 n 𝑎 1 , 𝑎 2 , ⋯ , 𝑎 𝑛 a 1 , a 2 , ⋯ , a n 1   ≤ 𝑖   ≤ 𝑛 1 ≤ i ≤ n 𝑓 𝑖 f i 
 ∀ 𝑗 ∈ [ 1 , 𝑛 ] : 𝑎 𝑗 ≤ 𝑎 𝑖 + 𝑓 𝑖 − √ | 𝑖 − 𝑗 | . ∀ j ∈ [ 1 , n ] : a j ≤ a i + f i − | i − j | . 思路  显然,经过不等式变形,我们可以得到待求整数 𝑓 𝑖   = m a x 𝑗 { 𝑎 𝑗   + √ | 𝑖 − 𝑗 |   − 𝑎 𝑖 } f i = max j { a j + | i − j | − a i } 𝑗   ≤ 𝑖 j ≤ i 
 𝑓 𝑖 = − m i n 𝑗 ≤ 𝑖 { − 𝑎 𝑗 − √ 𝑖 − 𝑗 + 𝑎 𝑖 } . f i = − min j ≤ i { − a j − i − j + a i } . 根据 − √ 𝑥 − x 𝑤 ( 𝑙 , 𝑟 )   =   − 𝑎 𝑙   − √ 𝑟 − 𝑙   + 𝑎 𝑟 w ( l , r ) = − a l − r − l + a r 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 
实现   1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 #include   <algorithm> 
#include   <cmath> 
#include   <deque> 
#include   <iostream> 
#define all \ 
  for (auto i : {&q, &l, &r}) (*i) 
using   namespace   std ; 
int   n ,   a [ 500009 ],   ans [ 500009 ]; 
deque < int >   q ,   l ,   r ; 
double   f ( int   i ,   int   j )   {   return   a [ i ]   +   sqrtl ( j   -   i );   } 
void   work ()   { 
   all . clear (); 
   for   ( int   i   =   0 ;   i   <   n ;   ++ i )   { 
     if   ( q . size ()   &&   r . front ()   <   i )   all . pop_front ();    // 队首出队 
     if   ( q . size ())   l . front ()   =   i ; 
     for   (;   q . size ()   &&   f ( q . back (),   l . back ())   <=   f ( i ,   l . back ());)    // 队尾出队 
       all . pop_back (); 
     if   ( q . empty ())    // 入队 
       q . emplace_back ( i ),   l . emplace_back ( i ),   r . emplace_back ( n ); 
     else   if   ( f ( q . back (),   n )   <   f ( i ,   n ))   { 
       int   ll   =   l . back (),   rr   =   n ,   mid ; 
       for   (;   ll   <=   rr ;)   { 
         mid   =   ( ll   +   rr )   >>   1 ; 
         if   ( f ( q . back (),   mid )   <   f ( i ,   mid )) 
           rr   =   mid   -   1 ; 
         else 
           ll   =   mid   +   1 ; 
       } 
       r . back ()   =   rr ; 
       q . emplace_back ( i ),   l . emplace_back ( ll ),   r . emplace_back ( n ); 
     } 
     ans [ i ]   =   max ( ans [ i ],   ( int )( ceil ( f ( q . front (),   i )))   -   a [ i ]); 
   } 
} 
int   main ()   { 
   cin   >>   n ; 
   for   ( int   i   =   0 ;   i   <   n ;   cin   >>   a [ i ++ ]); 
   work (); 
   reverse ( a ,   a   +   n ); 
   reverse ( ans ,   ans   +   n ); 
   work (); 
   reverse ( ans ,   ans   +   n ); 
   for   ( int   i   =   0 ;   i   <   n ;   cout   <<   ans [ i ++ ]   <<   '\n' ); 
} 
区间分拆问题 考虑将某个区间拆分成若干个子区间的问题。形式化地说,将给定区间 [ 1 , 𝑛 ] [ 1 , n ] [ 𝑎 1 , 𝑏 1 ] , ⋯ , [ 𝑎 𝑘 , 𝑏 𝑘 ] [ a 1 , b 1 ] , ⋯ , [ a k , b k ] 𝑎 1   = 1 a 1 = 1 𝑏 𝑘   = 𝑛 b k = n 𝑏 𝑖   + 1   = 𝑎 𝑖 + 1 b i + 1 = a i + 1 𝑖   < 𝑘 i < k ∑ 𝑘 𝑖 = 1 𝑤 ( 𝑎 𝑖 , 𝑏 𝑖 ) ∑ i = 1 k w ( a i , b i ) 
𝑓 ( 𝑖 ) = m i n 1 ≤ 𝑗 ≤ 𝑖 𝑓 ( 𝑗 − 1 ) + 𝑤 ( 𝑗 , 𝑖 ) ( 1 ≤ 𝑖 ≤ 𝑛 ) f ( i ) = min 1 ≤ j ≤ i f ( j − 1 ) + w ( j , i ) ( 1 ≤ i ≤ n ) 这里,𝑓 ( 0 )   = 0 f ( 0 ) = 0 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) 𝑓 ( 𝑗   − 1 )   + 𝑤 ( 𝑗 , 𝑖 ) f ( j − 1 ) + w ( j , i ) 𝑗 j 𝑖 i 𝑂 ( 𝑛 l o g  𝑛 ) O ( n log  n ) 
限制区间个数的情形 上述问题可以加强为限制区间个数的情形,即问题指定将区间拆分成 𝑚 m 
𝑓 ( 𝑘 , 𝑖 ) = m i n 1 ≤ 𝑗 ≤ 𝑖 𝑓 ( 𝑘 − 1 , 𝑗 − 1 ) + 𝑤 ( 𝑗 , 𝑖 ) ( 1 ≤ 𝑘 ≤ 𝑚 ,   1 ≤ 𝑖 ≤ 𝑛 ) ( 2 ) (2) f ( k , i ) = min 1 ≤ j ≤ i f ( k − 1 , j − 1 ) + w ( j , i ) ( 1 ≤ k ≤ m ,   1 ≤ i ≤ n ) 这里,𝑓 ( 0 , 0 )   = 0 f ( 0 , 0 ) = 0 𝑓 ( 0 , 𝑖 )   = 𝑓 ( 𝑘 , 0 )   = ∞ f ( 0 , i ) = f ( k , 0 ) = ∞ 1   ≤ 𝑘   ≤ 𝑚 1 ≤ k ≤ m 1   ≤ 𝑖   ≤ 𝑛 1 ≤ i ≤ n 𝑓 ( 𝑘   − 1 , 𝑗   − 1 )   + 𝑤 ( 𝑗 , 𝑖 ) f ( k − 1 , j − 1 ) + w ( j , i ) 𝑖 i 𝑂 ( 𝑚 𝑛 l o g  𝑛 ) O ( m n log  n ) 
对于这一问题,利用决策单调性,实际上还存在其他的优化算法。第二种优化思路依赖于如下结果。这种优化算法和下文详细描述的 Knuth 优化算法十分相似。
定理 2  若 𝑤 w o p t  ( 𝑘   − 1 , 𝑖 )   ≤ o p t  ( 𝑘 , 𝑖 )   ≤ o p t  ( 𝑘 , 𝑖   + 1 ) opt  ( k − 1 , i ) ≤ opt  ( k , i ) ≤ opt  ( k , i + 1 ) 
证明  第二个不等式只是第 𝑘 k 
 下证 o p t  ( 𝑘 , 𝑖 )   ≤ o p t  ( 𝑘   + 1 , 𝑖 ) opt  ( k , i ) ≤ opt  ( k + 1 , i ) [ 1 , 𝑖 ] [ 1 , i ] [ 𝑎 𝑘 , 𝑑 𝑘 ] , ⋯ , [ 𝑎 1 , 𝑑 1 ] [ a k , d k ] , ⋯ , [ a 1 , d 1 ] [ 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ] , ⋯ , [ 𝑏 1 , 𝑐 1 ] [ b k + 1 , c k + 1 ] , ⋯ , [ b 1 , c 1 ] 𝑑 𝑗 d j 𝑐 𝑗 c j [ 𝑎 𝑗 , 𝑖 ] [ a j , i ] [ 𝑏 𝑗 , 𝑖 ] [ b j , i ] 𝑗 j 𝑎 𝑗 − 1   > 𝑏 𝑗 − 1 a j − 1 > b j − 1 𝑑 𝑗   > 𝑐 𝑗 d j > c j 𝑎 𝑗   > 𝑏 𝑗 a j > b j 𝑎 1   > 𝑏 1 a 1 > b 1 𝑎 𝑘   > 𝑏 𝑘 a k > b k 
 第一个不等式可以另证如下。同样考虑上面证明中的两个分划。如果所证命题不成立,则有 𝑎 1   > 𝑏 1 a 1 > b 1 𝑎 𝑘   < 𝑏 𝑘 a k < b k 𝑗   > 1 j > 1 𝑎 𝑗   ≤ 𝑏 𝑗 a j ≤ b j 𝑎 𝑗 − 1   > 𝑏 𝑗 − 1 a j − 1 > b j − 1 𝑑 𝑗   > 𝑐 𝑗 d j > c j 𝑎 𝑗   ≤ 𝑏 𝑗   ≤ 𝑐 𝑗   < 𝑑 𝑗 a j ≤ b j ≤ c j < d j [ 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ] , ⋯ , [ 𝑏 𝑗 + 1 , 𝑐 𝑗 + 1 ] , [ 𝑏 𝑗 , 𝑑 𝑗 ] , [ 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ] , ⋯ , [ 𝑎 1 , 𝑑 1 ] [ b k + 1 , c k + 1 ] , ⋯ , [ b j + 1 , c j + 1 ] , [ b j , d j ] , [ a j − 1 , d j − 1 ] , ⋯ , [ a 1 , d 1 ] ( 𝑘   + 1 ) ( k + 1 ) 
 𝑤 ( 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ) + ⋯ + 𝑤 ( 𝑏 𝑗 + 1 , 𝑐 𝑗 + 1 ) + 𝑤 ( 𝑏 𝑗 , 𝑐 𝑗 ) + 𝑤 ( 𝑏 𝑗 − 1 , 𝑐 𝑗 − 1 ) + ⋯ + 𝑤 ( 𝑏 1 , 𝑐 1 ) ≤ 𝑤 ( 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ) + ⋯ + 𝑤 ( 𝑏 𝑗 + 1 , 𝑐 𝑗 + 1 ) + 𝑤 ( 𝑏 𝑗 , 𝑑 𝑗 ) + 𝑤 ( 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ) + ⋯ + 𝑤 ( 𝑎 1 , 𝑑 1 ) . w ( b k + 1 , c k + 1 ) + ⋯ + w ( b j + 1 , c j + 1 ) + w ( b j , c j ) + w ( b j − 1 , c j − 1 ) + ⋯ + w ( b 1 , c 1 ) ≤ w ( b k + 1 , c k + 1 ) + ⋯ + w ( b j + 1 , c j + 1 ) + w ( b j , d j ) + w ( a j − 1 , d j − 1 ) + ⋯ + w ( a 1 , d 1 ) . 同样地,考虑分拆 [ 𝑎 𝑘 , 𝑑 𝑘 ] , ⋯ , [ 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ] , [ 𝑎 𝑗 , 𝑐 𝑗 ] , [ 𝑏 𝑗 − 1 , 𝑐 𝑗 − 1 ] , ⋯ , [ 𝑏 1 , 𝑐 1 ] [ a k , d k ] , ⋯ , [ a j + 1 , d j + 1 ] , [ a j , c j ] , [ b j − 1 , c j − 1 ] , ⋯ , [ b 1 , c 1 ] 𝑘 k 
 𝑤 ( 𝑎 𝑘 , 𝑑 𝑘 ) + ⋯ + 𝑤 ( 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ) + 𝑤 ( 𝑎 𝑗 , 𝑑 𝑗 ) + 𝑤 ( 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ) + ⋯ + 𝑤 ( 𝑎 1 , 𝑑 1 ) < 𝑤 ( 𝑎 𝑘 , 𝑑 𝑘 ) + ⋯ + 𝑤 ( 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ) + 𝑤 ( 𝑎 𝑗 , 𝑐 𝑗 ) + 𝑤 ( 𝑏 𝑗 − 1 , 𝑐 𝑗 − 1 ) + ⋯ + 𝑤 ( 𝑏 1 , 𝑐 1 ) . w ( a k , d k ) + ⋯ + w ( a j + 1 , d j + 1 ) + w ( a j , d j ) + w ( a j − 1 , d j − 1 ) + ⋯ + w ( a 1 , d 1 ) < w ( a k , d k ) + ⋯ + w ( a j + 1 , d j + 1 ) + w ( a j , c j ) + w ( b j − 1 , c j − 1 ) + ⋯ + w ( b 1 , c 1 ) . 此时,不等号是严格的,因为 𝑎 1   > 𝑏 1 a 1 > b 1 𝑎 1 a 1 𝑘 k 𝑤 ( 𝑏 𝑗 , 𝑐 𝑗 )   + 𝑤 ( 𝑎 𝑗 , 𝑑 𝑗 )   < 𝑤 ( 𝑏 𝑗 , 𝑑 𝑗 )   + 𝑤 ( 𝑎 𝑗 , 𝑐 𝑗 ) w ( b j , c j ) + w ( a j , d j ) < w ( b j , d j ) + w ( a j , c j ) 
利用这一结果,我们可以限制决策 𝑗 j 𝑘 k 𝑖 i 𝑗 j 𝑂 ( 𝑛 ( 𝑛   + 𝑚 ) ) O ( n ( n + m ) ) 
注意  这里算法复杂度不是 𝑂 ( 𝑛 𝑚 ) O ( n m ) 𝑛   × 𝑚 n × m ( 𝑖 , 𝑘 ) ( i , k ) o p t  ( 𝑘   − 1 , 𝑖 )   ≤ 𝑗   ≤ o p t  ( 𝑘 , 𝑖   + 1 ) opt  ( k − 1 , i ) ≤ j ≤ opt  ( k , i + 1 ) 𝑖   − 𝑘 i − k 𝑂 ( 𝑛 ) O ( n ) ( 𝑛   + 𝑚 ) ( n + m ) 𝑂 ( 𝑛 ( 𝑛   + 𝑚 ) ) O ( n ( n + m ) ) 
最后一种优化方法来源于如下的观察。
定理 3  若 𝑤 w 𝑔 ( 𝑘 )   : = 𝑓 ( 𝑛 , 𝑘 ) g ( k ) := f ( n , k ) 𝑘 k 
证明  下证 𝑔 ( 𝑘   − 1 )   + 𝑔 ( 𝑘   + 1 )   ≥ 2 𝑔 ( 𝑘 ) g ( k − 1 ) + g ( k + 1 ) ≥ 2 g ( k ) ( 𝑘   − 1 ) ( k − 1 ) ( 𝑘   + 1 ) ( k + 1 ) [ 𝑎 1 , 𝑑 1 ] , ⋯ , [ 𝑎 𝑘 − 1 , 𝑑 𝑘 − 1 ] [ a 1 , d 1 ] , ⋯ , [ a k − 1 , d k − 1 ] [ 𝑏 1 , 𝑐 1 ] , ⋯ , [ 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ] [ b 1 , c 1 ] , ⋯ , [ b k + 1 , c k + 1 ] 1   ≤ 𝑗   ≤ 𝑘   − 1 1 ≤ j ≤ k − 1 𝑐 𝑗 + 1   ≤ 𝑑 𝑗 c j + 1 ≤ d j 𝑐 𝑘   < 𝑛   = 𝑑 𝑘 − 1 c k < n = d k − 1 𝑏 𝑗 + 1   > 𝑎 𝑗 b j + 1 > a j 𝑎 𝑗   < 𝑏 𝑗 + 1   ≤ 𝑐 𝑗 + 1   ≤ 𝑑 𝑗 a j < b j + 1 ≤ c j + 1 ≤ d j 
 [ 𝑎 1 , 𝑑 1 ] , ⋯ , [ 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ] , [ 𝑎 𝑗 , 𝑐 𝑗 + 1 ] , [ 𝑏 𝑗 + 2 , 𝑐 𝑗 + 2 ] , ⋯ , [ 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ] , [ 𝑏 1 , 𝑐 1 ] , ⋯ , [ 𝑏 𝑗 , 𝑐 𝑗 ] , [ 𝑏 𝑗 + 1 , 𝑑 𝑗 ] , [ 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ] , ⋯ , [ 𝑎 𝑘 − 1 , 𝑑 𝑘 − 1 ] . [ a 1 , d 1 ] , ⋯ , [ a j − 1 , d j − 1 ] , [ a j , c j + 1 ] , [ b j + 2 , c j + 2 ] , ⋯ , [ b k + 1 , c k + 1 ] , [ b 1 , c 1 ] , ⋯ , [ b j , c j ] , [ b j + 1 , d j ] , [ a j + 1 , d j + 1 ] , ⋯ , [ a k − 1 , d k − 1 ] . 两个所得区间都是 𝑘 k 
 2 𝑔 ( 𝑘 ) ≤ 𝑤 ( 𝑎 1 , 𝑑 1 ) + ⋯ + 𝑤 ( 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ) + 𝑤 ( 𝑎 𝑗 , 𝑐 𝑗 + 1 ) + 𝑤 ( 𝑏 𝑗 + 2 , 𝑐 𝑗 + 2 ) + ⋯ + 𝑤 ( 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ) + 𝑤 ( 𝑏 1 , 𝑐 1 ) + ⋯ + 𝑤 ( 𝑏 𝑗 , 𝑐 𝑗 ) + 𝑤 ( 𝑏 𝑗 + 1 , 𝑑 𝑗 ) + 𝑤 ( 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ) + ⋯ + 𝑤 ( 𝑎 𝑘 − 1 , 𝑑 𝑘 − 1 ) ≤ 𝑤 ( 𝑎 1 , 𝑑 1 ) + ⋯ + 𝑤 ( 𝑎 𝑗 − 1 , 𝑑 𝑗 − 1 ) + 𝑤 ( 𝑎 𝑗 , 𝑑 𝑗 ) + 𝑤 ( 𝑎 𝑗 + 1 , 𝑑 𝑗 + 1 ) + ⋯ + 𝑤 ( 𝑎 𝑘 − 1 , 𝑑 𝑘 − 1 ) + 𝑤 ( 𝑏 1 , 𝑐 1 ) + ⋯ + 𝑤 ( 𝑏 𝑗 , 𝑐 𝑗 ) + 𝑤 ( 𝑏 𝑗 + 1 , 𝑐 𝑗 + 1 ) + 𝑤 ( 𝑏 𝑗 + 2 , 𝑐 𝑗 + 2 ) + ⋯ + 𝑤 ( 𝑏 𝑘 + 1 , 𝑐 𝑘 + 1 ) = 𝑔 ( 𝑘 − 1 ) + 𝑔 ( 𝑘 + 1 ) . 2 g ( k ) ≤ w ( a 1 , d 1 ) + ⋯ + w ( a j − 1 , d j − 1 ) + w ( a j , c j + 1 ) + w ( b j + 2 , c j + 2 ) + ⋯ + w ( b k + 1 , c k + 1 ) + w ( b 1 , c 1 ) + ⋯ + w ( b j , c j ) + w ( b j + 1 , d j ) + w ( a j + 1 , d j + 1 ) + ⋯ + w ( a k − 1 , d k − 1 ) ≤ w ( a 1 , d 1 ) + ⋯ + w ( a j − 1 , d j − 1 ) + w ( a j , d j ) + w ( a j + 1 , d j + 1 ) + ⋯ + w ( a k − 1 , d k − 1 ) + w ( b 1 , c 1 ) + ⋯ + w ( b j , c j ) + w ( b j + 1 , c j + 1 ) + w ( b j + 2 , c j + 2 ) + ⋯ + w ( b k + 1 , c k + 1 ) = g ( k − 1 ) + g ( k + 1 ) . 这里第二个不等式正是四边形不等式。所求凸性由此得证。
这一结论保证了可以通过 WQS 二分(国外称 Aliens Trick)的方法解决此问题。具体来说,考虑带参的成本函数 𝑤 𝑐 ( 𝑗 , 𝑖 )   : = 𝑤 ( 𝑗 , 𝑖 )   + 𝑐 w c ( j , i ) := w ( j , i ) + c 𝑓 𝑐 ( 𝑛 ) f c ( n ) 𝑐 c 𝑚 m 𝑐 c 𝑓 ( 𝑛 , 𝑚 )   = 𝑓 𝑐 ( 𝑛 )   − 𝑐 𝑚 f ( n , m ) = f c ( n ) − c m 𝑐 c WQS 二分  页面。这一算法的时间复杂度为 𝑂 ( 𝑛 l o g  𝑛 l o g  𝐶 ) O ( n log  n log  C ) 𝐶 C 
对于限制区间个数的区间分拆问题的三种算法,在不同的数据范围时表现各有优劣,需要结合具体的题目选择合适的算法。
例题 2:P4767 [IOI2000] 邮局 加强版  P6246 [IOI2000] 邮局 加强版 加强版   高速公路旁边有一些村庄。高速公路表示为整数轴,每个村庄的位置用单个整数坐标标识。没有两个在同样地方的村庄。两个位置之间的距离是其整数坐标差的绝对值。
 邮局将建在一些,但不一定是所有的村庄中。为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局之间的距离总和最小。
 你要编写一个程序,已知村庄的位置和邮局的数量,计算每个村庄和最近的邮局之间所有距离的最小可能的总和。
 思路  每个村庄有其最近的邮局,那么每个邮局也有其管辖的村庄,易知这是一个区间。
 考虑把这 𝑛 n 𝑚 m 
 根据数学知识,对于区间 [ 𝑖 , 𝑗 ] [ i , j ] ⌊ 𝑖 + 𝑗 2 ⌋ ⌊ i + j 2 ⌋ 𝑤 ( 𝑖 , 𝑗 ) w ( i , j ) 
 问题转化为限制区间个数的区间分拆问题。可以证明,𝑤 w 
实现 1,前文第二种优化,复杂度 𝑂 ( 𝑛 ( 𝑛   + 𝑚 ) ) O ( n ( n + m ) )    1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 #include   <iostream> 
constexpr   int   N   =   3009 ; 
constexpr   int   M   =   309 ; 
using   namespace   std ; 
int   n ,   m ,   a [ N ],   s [ N ],   g [ M ][ N ],   p [ M ][ N ]; 
int   f ( int   i ,   int   j )   { 
   int   k   =   ( i   +   j )   >>   1 ; 
   return   a [ k ]   *   ( k   -   i   +   1 )   -   ( s [ k ]   -   s [ i   -   1 ])   +   ( s [ j ]   -   s [ k ])   - 
          a [ k ]   *   ( j   -   k ); 
} 
int   main ()   { 
   cin   >>   n   >>   m ; 
   for   ( int   i   =   1 ;   i   <=   n ;   cin   >>   a [ i ],   s [ i ]   =   s [ i   -   1 ]   +   a [ i ],   ++ i ); 
   for   ( int   i   =   1 ;   i   <=   n ;   ++ i )   g [ 0 ][ i ]   =   1   <<   30 ,   p [ m   +   1 ][ i ]   =   i ; 
   for   ( int   i   =   1 ;   i   <=   m ;   ++ i )   p [ i ][ 0 ]   =   1 ; 
   for   ( int   i   =   1 ;   i   <=   n ;   ++ i ) 
     for   ( int   j   =   m ;   j ;   -- j )   { 
       g [ j ][ i ]   =   1   <<   30 ; 
       for   ( int   k   =   p [ j ][ i   -   1 ];   k   <=   p [ j   +   1 ][ i ];   ++ k )   { 
         int   tmp   =   g [ j   -   1 ][ k   -   1 ]   +   f ( k ,   i ); 
         if   ( tmp   <   g [ j ][ i ])   g [ j ][ i ]   =   tmp ,   p [ j ][ i ]   =   k ; 
       } 
     } 
   cout   <<   g [ m ][ n ]; 
} 
实现 2,WQS 二分,复杂度 𝑂 ( 𝑛 l o g  𝑛 l o g  𝐶 ) O ( n log  n log  C )    1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 #include   <deque> 
#include   <iostream> 
#define all \ 
  for (auto i : {&q, &l, &r}) (*i) 
using   namespace   std ; 
long   long   n ,   m ,   a [ 500009 ],   s [ 500009 ],   u ,   v ,   w ,   sum [ 500009 ],   cnt [ 500009 ]; 
deque < int >   q ,   l ,   r ; 
long   long   f ( int   i ,   int   j )   { 
   int   k   =   ( i   +   j )   >>   1 ; 
   return   sum [ i   -   1 ]   +   v   +   a [ k ]   *   ( k   -   i   +   1 )   -   ( s [ k ]   -   s [ i   -   1 ])   + 
          ( s [ j ]   -   s [ k ])   -   a [ k ]   *   ( j   -   k ); 
} 
void   work ()   { 
   all . clear (); 
   for   ( int   i   =   1 ;   i   <=   n ;   ++ i )   { 
     if   ( q . size ()   &&   r . front ()   <   i )   all . pop_front ();    // 队首出队 
     if   ( q . size ())   l . front ()   =   i ; 
     for   (;   q . size ()   &&   f ( q . back (),   l . back ())   >=   f ( i ,   l . back ());)    // 队尾出队 
       all . pop_back (); 
     if   ( q . empty ())    // 入队 
       q . emplace_back ( i ),   l . emplace_back ( i ),   r . emplace_back (( int ) n ); 
     else   if   ( f ( q . back (),   n )   >=   f ( i ,   n ))   { 
       int   ll   =   l . back (),   rr   =   n ,   mid ; 
       for   (;   ll   <=   rr ;)   { 
         mid   =   ( ll   +   rr )   >>   1 ; 
         if   ( f ( q . back (),   mid )   >=   f ( i ,   mid )) 
           rr   =   mid   -   1 ; 
         else 
           ll   =   mid   +   1 ; 
       } 
       r . back ()   =   rr ; 
       q . emplace_back ( i ),   l . emplace_back ( ll ),   r . emplace_back (( int ) n ); 
     } 
     sum [ i ]   =   f ( q . front (),   i ); 
     cnt [ i ]   =   cnt [ q . front ()   -   1 ]   +   1 ; 
   } 
} 
int   main ()   { 
   cin   >>   n   >>   m ; 
   for   ( int   i   =   1 ;   i   <=   n ;   cin   >>   a [ i ],   s [ i ]   =   s [ i   -   1 ]   +   a [ i ],   ++ i ); 
   for   ( w   =   2e12 ;   u   <=   w ;)   {    // wqs二分 
     v   =   ( u   +   w )   >>   1 ; 
     work (); 
     if   ( cnt [ n ]   <   m ) 
       w   =   v   -   1 ; 
     else 
       u   =   v   +   1 ; 
   } 
   v   =   w ; 
   work (); 
   cout   <<   sum [ n ]   -   m   *   v ; 
} 
区间合并问题 另一类可以通过四边形不等式优化的动态规划问题是区间合并问题,即要将 𝑛 n [ 𝑖 , 𝑖 ] [ i , i ] [ 1 , 𝑛 ] [ 1 , n ] [ 𝑗 , 𝑘 ] [ j , k ] [ 𝑘   + 1 , 𝑖 ] [ k + 1 , i ] 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) 
𝑓 ( 𝑗 , 𝑖 ) = m i n 𝑗 ≤ 𝑘 < 𝑖 𝑓 ( 𝑗 , 𝑘 ) + 𝑓 ( 𝑘 + 1 , 𝑖 ) + 𝑤 ( 𝑗 , 𝑖 ) ( 1 ≤ 𝑗 < 𝑖 ≤ 𝑛 ) ( 3 ) (3) f ( j , i ) = min j ≤ k < i f ( j , k ) + f ( k + 1 , i ) + w ( j , i ) ( 1 ≤ j < i ≤ n ) 这里给定任意初始成本 𝑓 ( 𝑖 , 𝑖 )   = 𝑤 ( 𝑖 , 𝑖 ) f ( i , i ) = w ( i , i ) 𝑂 ( 𝑛 3 ) O ( n 3 ) 𝑂 ( 𝑛 2 ) O ( n 2 ) 
除了四边形不等式以外,区间合并问题的决策单调性还要求成本函数满足区间包含单调性。
区间包含单调性 :如果对于任意 𝑎   ≤ 𝑏   ≤ 𝑐   ≤ 𝑑 a ≤ b ≤ c ≤ d 𝑤 ( 𝑏 , 𝑐 ) ≤ 𝑤 ( 𝑎 , 𝑑 ) , w ( b , c ) ≤ w ( a , d ) , 则称函数 𝑤 w 
这实质是成本函数的一阶条件,即 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) 𝑗 j 𝑖 i 
引理 1  若 𝑤 w 𝑓 ( 𝑗 , 𝑖 ) f ( j , i ) 
证明  不妨设 𝑎   ≤ 𝑏   ≤ 𝑐   ≤ 𝑑 a ≤ b ≤ c ≤ d 𝑓 ( 𝑎 , 𝑑 )   + 𝑓 ( 𝑏 , 𝑐 )   ≥ 𝑓 ( 𝑎 , 𝑐 )   + 𝑓 ( 𝑏 , 𝑑 ) f ( a , d ) + f ( b , c ) ≥ f ( a , c ) + f ( b , d ) 𝑑   − 𝑎 d − a 𝑎   = 𝑏 a = b 𝑐   = 𝑑 c = d 𝑑 ′   = o p t  ( 𝑎 , 𝑑 ) d ′ = opt  ( a , d ) 
 第一种情况,𝑐   ≤ 𝑑 ′ c ≤ d ′ 𝑑 ′   < 𝑏 d ′ < b [ 𝑏 , 𝑐 ] [ b , c ] [ 𝑎 , 𝑑 ′ ] [ a , d ′ ] [ 𝑑 ′   + 1 , 𝑑 ] [ d ′ + 1 , d ] 
 不妨假设 𝑐   ≤ 𝑑 ′ c ≤ d ′ 
 𝑓 ( 𝑎 , 𝑑 ) + 𝑓 ( 𝑏 , 𝑐 ) = 𝑓 ( 𝑎 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑎 , 𝑑 ) + 𝑓 ( 𝑏 , 𝑐 ) ≥ 𝑓 ( 𝑎 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑎 , 𝑑 ) ≥ 𝑓 ( 𝑎 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑏 , 𝑑 ) ≥ 𝑓 ( 𝑎 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ) . f ( a , d ) + f ( b , c ) = f ( a , d ′ ) + f ( d ′ + 1 , d ) + w ( a , d ) + f ( b , c ) ≥ f ( a , c ) + f ( b , d ′ ) + f ( d ′ + 1 , d ) + w ( a , d ) ≥ f ( a , c ) + f ( b , d ′ ) + f ( d ′ + 1 , d ) + w ( b , d ) ≥ f ( a , c ) + f ( b , d ) . 这里,第一个不等式来自于归纳假设 𝑓 ( 𝑎 , 𝑐 )   + 𝑓 ( 𝑏 , 𝑑 ′ )   ≤ 𝑓 ( 𝑎 , 𝑑 ′ )   + 𝑓 ( 𝑏 , 𝑐 ) f ( a , c ) + f ( b , d ′ ) ≤ f ( a , d ′ ) + f ( b , c ) 𝑤 ( 𝑏 , 𝑑 )   ≤ 𝑤 ( 𝑎 , 𝑑 ) w ( b , d ) ≤ w ( a , d ) 𝑓 ( 𝑏 , 𝑑 )   ≤ 𝑓 ( 𝑏 , 𝑑 ′ )   + 𝑓 ( 𝑑 ′   + 1 , 𝑑 )   + 𝑤 ( 𝑏 , 𝑑 ) f ( b , d ) ≤ f ( b , d ′ ) + f ( d ′ + 1 , d ) + w ( b , d ) 
 第二种情况,𝑏   ≤ 𝑑 ′   < 𝑐 b ≤ d ′ < c 𝑑 ′ d ′ [ 𝑏 , 𝑐 ] [ b , c ] 𝑐 ′   = o p t  ( 𝑏 , 𝑐 ) c ′ = opt  ( b , c ) 
 不妨假设 𝑐 ′   ≤ 𝑑 ′ c ′ ≤ d ′ [ 𝑏 , 𝑐 ′ ] [ b , c ′ ] [ 𝑎 , 𝑑 ′ ] [ a , d ′ ] 
 𝑓 ( 𝑎 , 𝑑 ) + 𝑓 ( 𝑏 , 𝑐 ) = 𝑓 ( 𝑎 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑎 , 𝑑 ) + 𝑓 ( 𝑏 , 𝑐 ′ ) + 𝑓 ( 𝑐 ′ + 1 , 𝑐 ) + 𝑤 ( 𝑏 , 𝑐 ) ≥ 𝑓 ( 𝑎 , 𝑐 ′ ) + 𝑓 ( 𝑐 ′ + 1 , 𝑐 ) + 𝑤 ( 𝑏 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑎 , 𝑑 ) ≥ 𝑓 ( 𝑎 , 𝑐 ′ ) + 𝑓 ( 𝑐 ′ + 1 , 𝑐 ) + 𝑤 ( 𝑎 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ′ ) + 𝑓 ( 𝑑 ′ + 1 , 𝑑 ) + 𝑤 ( 𝑏 , 𝑑 ) ≥ 𝑓 ( 𝑎 , 𝑐 ) + 𝑓 ( 𝑏 , 𝑑 ) . f ( a , d ) + f ( b , c ) = f ( a , d ′ ) + f ( d ′ + 1 , d ) + w ( a , d ) + f ( b , c ′ ) + f ( c ′ + 1 , c ) + w ( b , c ) ≥ f ( a , c ′ ) + f ( c ′ + 1 , c ) + w ( b , c ) + f ( b , d ′ ) + f ( d ′ + 1 , d ) + w ( a , d ) ≥ f ( a , c ′ ) + f ( c ′ + 1 , c ) + w ( a , c ) + f ( b , d ′ ) + f ( d ′ + 1 , d ) + w ( b , d ) ≥ f ( a , c ) + f ( b , d ) . 这里,第一个不等式来自于归纳假设 𝑓 ( 𝑎 , 𝑐 ′ )   + 𝑓 ( 𝑏 , 𝑑 ′ )   ≤ 𝑓 ( 𝑎 , 𝑑 ′ )   + 𝑓 ( 𝑏 , 𝑐 ′ ) f ( a , c ′ ) + f ( b , d ′ ) ≤ f ( a , d ′ ) + f ( b , c ′ ) 𝑤 ( 𝑎 , 𝑐 )   + 𝑤 ( 𝑏 , 𝑑 )   ≤ 𝑤 ( 𝑎 , 𝑑 )   + 𝑤 ( 𝑏 , 𝑐 ) w ( a , c ) + w ( b , d ) ≤ w ( a , d ) + w ( b , c ) 𝑓 ( 𝑎 , 𝑐 ) f ( a , c ) 𝑓 ( 𝑏 , 𝑑 ) f ( b , d ) 
定理 4  若 𝑤 w o p t  ( 𝑗 , 𝑖 ) opt  ( j , i ) 
 o p t  ( 𝑗 , 𝑖 − 1 ) ≤ o p t  ( 𝑗 , 𝑖 ) ≤ o p t  ( 𝑗 + 1 , 𝑖 ) . ( 𝑗 + 1 < 𝑖 ) opt  ( j , i − 1 ) ≤ opt  ( j , i ) ≤ opt  ( j + 1 , i ) . ( j + 1 < i ) 证明  引理 1 已经证得 𝑓 ( 𝑗 , 𝑖 ) f ( j , i ) 𝑓 ( 𝑗 , 𝑘 )   + 𝑓 ( 𝑘   + 1 , 𝑖 )   + 𝑤 ( 𝑗 , 𝑖 ) f ( j , k ) + f ( k + 1 , i ) + w ( j , i ) 𝑗 j ( 𝑘 , 𝑖 ) ( k , i ) o p t  ( 𝑗 , 𝑖   − 1 )   ≤ o p t  ( 𝑗 , 𝑖 ) opt  ( j , i − 1 ) ≤ opt  ( j , i ) ( 𝑘 , 𝑖 ) ( k , i ) 𝑖 i ( 𝑘 , 𝑗 ) ( k , j ) o p t  ( 𝑗 , 𝑖 )   ≤ o p t  ( 𝑗   + 1 , 𝑖 ) opt  ( j , i ) ≤ opt  ( j + 1 , i ) 
利用这一结论,同样可以限制决策点 𝑘 k 𝑖   − 𝑗   + 1 i − j + 1 [ 𝑗 , 𝑖 ] [ j , i ] o p t  ( 𝑗 , 𝑖   − 1 ) opt  ( j , i − 1 ) o p t  ( 𝑗   + 1 , 𝑖 ) opt  ( j + 1 , i ) 𝑘 k 𝑓 ( 𝑗 , 𝑖 ) f ( j , i ) o p t  ( 𝑗 , 𝑖 ) opt  ( j , i ) 𝑂 ( 𝑛 ) O ( n ) 𝑂 ( 𝑛 ) O ( n ) 𝑂 ( 𝑛 2 ) O ( n 2 ) 
核心代码  满足四边形不等式的函数类 为了更方便地证明一个函数满足四边形不等式,我们有以下几条性质:
性质 1 :若函数 𝑤 1 ( 𝑗 , 𝑖 ) w 1 ( j , i ) 𝑤 2 ( 𝑗 , 𝑖 ) w 2 ( j , i ) 𝑐 1 , 𝑐 2   ≥ 0 c 1 , c 2 ≥ 0 𝑐 1 𝑤 1   + 𝑐 2 𝑤 2 c 1 w 1 + c 2 w 2 
性质 2 :若存在函数 𝑓 ( 𝑥 ) f ( x ) 𝑔 ( 𝑥 ) g ( x ) 𝑤 ( 𝑗 , 𝑖 )   = 𝑓 ( 𝑗 )   − 𝑔 ( 𝑖 ) w ( j , i ) = f ( j ) − g ( i ) 𝑤 w 𝑓 f 𝑔 g 𝑤 w 
性质 3 :设 ℎ ( 𝑥 ) h ( x ) 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) ℎ ( 𝑤 ( 𝑗 , 𝑖 ) ) h ( w ( j , i ) ) 
性质 4 :设 ℎ ( 𝑥 ) h ( x ) 𝑤 ( 𝑗 , 𝑖 ) w ( j , i ) ℎ ( 𝑤 ( 𝑗 , 𝑖 ) ) h ( w ( j , i ) ) 
首先需要澄清一点,凸函数(Convex Function)的定义在国内教材中有分歧,此处的凸函数指的是下凸函数,即(可微时)一阶导数单调增加的函数。
证明  前两条性质根据定义很容易证明,下面证明第三条性质,性质四的证明过程类似。由于 ℎ ( 𝑥 ) h ( x ) ℎ ( 𝑤 ( 𝑗 , 𝑖 ) ) h ( w ( j , i ) ) 
 为此,下面考虑 𝑎   ≤ 𝑗   ≤ 𝑏   ≤ 𝑐   ≤ 𝑖   ≤ 𝑑 a ≤ j ≤ b ≤ c ≤ i ≤ d 
 Δ 𝑖 Δ 𝑗 ℎ ( 𝑤 ( 𝑗 , 𝑖 ) ) = ℎ ( 𝑤 ( 𝑏 , 𝑑 ) ) − ℎ ( 𝑤 ( 𝑎 , 𝑐 ) + Δ 𝑗 𝑤 ( 𝑗 , 𝑐 ) + Δ 𝑖 𝑤 ( 𝑎 , 𝑖 ) ) + ℎ ( 𝑤 ( 𝑎 , 𝑐 ) + Δ 𝑗 𝑤 ( 𝑗 , 𝑐 ) + Δ 𝑖 𝑤 ( 𝑎 , 𝑖 ) ) − ℎ ( 𝑤 ( 𝑎 , 𝑐 ) + Δ 𝑗 𝑤 ( 𝑗 , 𝑐 ) ) − ℎ ( 𝑤 ( 𝑎 , 𝑐 ) + Δ 𝑖 𝑤 ( 𝑎 , 𝑖 ) ) + ℎ ( 𝑤 ( 𝑎 , 𝑐 ) ) . Δ i Δ j h ( w ( j , i ) ) = h ( w ( b , d ) ) − h ( w ( a , c ) + Δ j w ( j , c ) + Δ i w ( a , i ) ) + h ( w ( a , c ) + Δ j w ( j , c ) + Δ i w ( a , i ) ) − h ( w ( a , c ) + Δ j w ( j , c ) ) − h ( w ( a , c ) + Δ i w ( a , i ) ) + h ( w ( a , c ) ) . 这里,根据区间单调性,Δ 𝑖 𝑤 ( 𝑎 , 𝑖 )   : = 𝑤 ( 𝑎 , 𝑑 )   − 𝑤 ( 𝑎 , 𝑐 )   ≥ 0 Δ i w ( a , i ) := w ( a , d ) − w ( a , c ) ≥ 0 Δ 𝑗 𝑤 ( 𝑗 , 𝑐 )   : = 𝑤 ( 𝑏 , 𝑐 )   − 𝑤 ( 𝑎 , 𝑐 )   ≤ 0 Δ j w ( j , c ) := w ( b , c ) − w ( a , c ) ≤ 0 ℎ ( 𝑥 ) h ( x ) 𝑡 1 , 𝑡 2   ≥ 0 t 1 , t 2 ≥ 0 ℎ ( 𝑥   + 𝑡 1   − 𝑡 2 )   − ℎ ( 𝑥   + 𝑡 1 )   ≤ ℎ ( 𝑥   − 𝑡 2 )   − ℎ ( 𝑥 ) h ( x + t 1 − t 2 ) − h ( x + t 1 ) ≤ h ( x − t 2 ) − h ( x ) 𝑤 ( 𝑏 , 𝑑 )   ≤ 𝑤 ( 𝑎 , 𝑐 )   + Δ 𝑗 𝑤 ( 𝑗 , 𝑐 )   + Δ 𝑖 𝑤 ( 𝑎 , 𝑖 )   = 𝑤 ( 𝑏 , 𝑐 )   + 𝑤 ( 𝑎 , 𝑑 )   − 𝑤 ( 𝑎 , 𝑐 ) w ( b , d ) ≤ w ( a , c ) + Δ j w ( j , c ) + Δ i w ( a , i ) = w ( b , c ) + w ( a , d ) − w ( a , c ) ℎ ( 𝑥 ) h ( x ) 
 这一证明实际是如下导数证明的离散版本。
 𝜕 2 𝜕 𝑥 𝜕 𝑦 ℎ ( 𝑤 ( 𝑥 , 𝑦 ) ) = ℎ ″ ( 𝑤 ( 𝑥 , 𝑦 ) ) 𝜕 𝜕 𝑥 𝑤 ( 𝑥 , 𝑦 ) 𝜕 𝜕 𝑦 𝑤 ( 𝑥 , 𝑦 ) + ℎ ′ ( 𝑤 ( 𝑥 , 𝑦 ) ) 𝜕 2 𝜕 𝑥 𝜕 𝑦 𝑤 ( 𝑥 , 𝑦 ) ≤ 0 . ∂ 2 ∂ x ∂ y h ( w ( x , y ) ) = h ″ ( w ( x , y ) ) ∂ ∂ x w ( x , y ) ∂ ∂ y w ( x , y ) + h ′ ( w ( x , y ) ) ∂ 2 ∂ x ∂ y w ( x , y ) ≤ 0. 这在 ℎ ′   ≥ 0 h ′ ≥ 0 ℎ ″   ≥ 0 h ″ ≥ 0 𝑤 𝑥   ≤ 0 w x ≤ 0 𝑤 𝑦   ≥ 0 w y ≥ 0 𝑤 𝑥 𝑦   ≤ 0 w x y ≤ 0 𝑤 w 
习题 参考资料 2025/10/13 16:54:57 ,更新历史 在 GitHub 上编辑此页! c-forrest , izlyforever , Ir1d , StudyingFather , Enter-tainer , Marcythm , ouuan , Yanjun-Zhao , Henry-ZHR , ksyx , NFLSCode , ranwen , sshwy , Xeonacid , billchenchina , CCXXXI , chang-wenxuan , Chrogeek , Elitedj , fps5283 , greyqz , HeRaNO , hsfzLZH1 , iamtwz , Menci , MingqiHuang , NachtgeistW , nanmenyangde , opsiff , shawlleyw , Tiphereth-A , TOMWT-qwq , TrisolarisHD , zryi2003 , zyf0726 CC BY-SA 4.0  和 SATA