四边形不等式优化
区间类(2D1D)动态规划中的应用
在区间类动态规划(如石子合并问题)中,我们经常遇到以下形式的 2D1D 状态转移方程:
直接简单实现状态转移,总时间复杂度将会达到
- 区间包含单调性:如果对于任意
,均有 成立,则称函数 对于区间包含关系具有单调性。 - 四边形不等式:如果对于任意
,均有 成立,则称函数 满足四边形不等式(简记为“交叉小于包含”)。若等号永远成立,则称函数 满足 四边形恒等式。
引理 1:若
定义
注意到,仅当
时 才有意义。因此我们有必要单独考虑 的情形。
首先注意到若
考虑对区间长度
-
(证明过程需要 满足区间包含单调性)-
若
则 ,由归纳法 ,两式相加再消去相同部分得到(下面最后一个不等式用到了 ): -
若
则 由归纳法 ,两式相加再消去相同部分得到(下面最后一个不等式用到了 ):
-
-
(仅需要 满足四边形不等式)-
若
,则 ,因此再由
和归纳假设知将前两个不等式累加,并将第三个不等式代入,可得
-
若
,则 ,因此再由
和归纳假设知将前两个不等式累加,并将第三个不等式代入,可得
-
综上所述,两种情形均有
定理 1:若状态
记
-
若
,则 ,因此根据四边形不等式有再根据
是状态 的最优决策点可知将以上两个不等式相加,得
即
,但这与 是最小的最优决策点矛盾,因此 。 -
若
,则 ,根据四边形不等式可得再根据
是状态 的最优决策点可知将以上两个不等式相加,得
即
,但这与 是最小的最优决策点矛盾,因此 。
因此,如果在计算状态
=== "C++"
```cpp
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; // 更新(最小)最优决策点
}
}
```
=== "Python"
```python
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 问题形式如下:
总共有
实际上此形式也有同样的结论,可以在
复杂度解决(且 只需要满足四边形不等式即可),读者可以模仿 2D1D 类似的给出证明。
令
我们可以更有效地解出所有状态。假设我们对于固定的
为了最小化运行时间,我们便需要应用分治法背后的思想。首先计算
1D1D 动态规划中的应用
除了经典的石子合并问题外,四边形不等式的性质在一类 1D1D 动态规划中也能得出决策单调性,从而优化状态转移的复杂度。考虑以下状态转移方程:
定理 2:若函数
记
又由于
将以上两个不等式相加,可得
即
但与 2D1D 动态规划中的情形不同,在这里我们根据决策单调性只能得出每次枚举
先考虑一种简单的情况,转移函数的值在动态规划前就已完全确定。即如下所示状态转移方程:
在这种情况下,我们定义过程
=== "C++"
```cpp
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);
}
```
=== "Python"
```python
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)
```
使用递归树的方法,容易分析出该分治算法的复杂度为
「POI2011」Lightning Conductor
给定一个长度为
显然,经过不等式变形,我们可以得到待求整数
根据
现在处理一般情况,即转移函数的值是在动态规划的过程中按照一定的拓扑序逐步确定的。此时我们需要改变思维方式,由“确定一个状态的最优决策”转化为“确定一个决策是哪些状态的最优决策“。具体可见上文的「单调栈优化 DP」。
满足四边形不等式的函数类
为了更方便地证明一个函数满足四边形不等式,我们有以下几条性质:
性质 1:若函数
性质 2:若存在函数
性质 3:设
性质 4:设
首先需要澄清一点,凸函数(Convex Function)的定义在国内教材中有分歧,此处的凸函数指的是(可微的)下凸函数,即一阶导数单调增加的函数。
前两条性质根据定义很容易证明,下面证明第三条性质,性质四的证明过程类似。
任取
任取
移项,并根据
记
设
即
回顾例题 1 中的
「HNOI2008」玩具装箱 toy
有
设
记
习题
- 「IOI2000」邮局
- Codeforces - Ciel and Gondolas(Be careful with I/O!)
- SPOJ - LARMY
- Codechef - CHEFAOR
- Hackerrank - Guardians of the Lunatics
- ACM ICPC World Finals 2017 - Money
参考资料
本页面主要译自英文版博文 Divide and Conquer DP。版权协议为 CC-BY-SA 4.0。
贡献者:@Menci@Codë@Shuhao@Ir1dXD@WenzelTian@忘怀@ranwen@izlyforever@mgt@Elitedj@nanmenyangde@zyj2297349886@sshwy@Henry-ZHR@yizr-cnyali@ouuan@Xeonacid
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用