四边形不等式优化
区间类(2D1D)动态规划中的应用¶
在区间类动态规划(如石子合并问题)中,我们经常遇到以下形式的 2D1D 状态转移方程:
直接简单实现状态转移,总时间复杂度将会达到
- 区间包含单调性:如果对于任意
l \leq l' \leq r' \leq r w(l',r') \leq w(l,r) w - 四边形不等式:如果对于任意
l_1\leq l_2 \leq r_1 \leq r_2 w(l_1,r_1)+w(l_2,r_2) \leq w(l_1,r_2) + w(l_2,r_1) w w
引理 1:若
定义
注意到,仅当
时 l_2 < r_1 才有意义。因此我们有必要单独考虑 v 的情形。 l_2 = r_1
首先注意到若
考虑对区间长度
-
l_1 < l_2 = r_1 < r_2 w -
若
u < r_1 f_{l_1, r_1} \leq f_{l_1, u} + f_{u + 1, r_1} + w(l_1, r_1) f_{u + 1, r_1} + f_{l_2, r_2} \leq f_{u + 1, r_2} + f_{l_2, r_1} w(l_1, r_1) < w(l_1, r_2) f_{l_1, r_1} + f_{l_2, r_2} \leq f_{l_1, u} + f_{u + 1, r_2} + f_{l_2, r_1} + w(l_1, r_1) \leq f_{l_1, r_2} + f_{l_2, r_1} -
若
u \geq r_1 f_{l_2, r_2} \leq f_{l_2, u} + f_{u + 1, r_2} + w(l_2, r_2) f_{l_1, r_1} + f_{l_2, u} \leq f_{l_1, u} + f_{l_2, r_1} w(l_2, r_2) < w(l_1, r_2) f_{l_1, r_1} + f_{l_2, r_2} \leq f_{l_1, u} + f_{l_2, r_1} + f_{u + 1, r_2} + w(l_2, r_2) \leq f_{l_1, r_2} + f_{l_2, r_1}
-
-
l_1 < l_2 < r_1 < r_2 w -
若
u\leq v l_1\leq u< r_1,\ l_2\leq v< r_2 \begin{aligned} f_{l_1,r_1} \leq g_{u,l_1,r_1} &= f_{l_1,u} + f_{u+1,r_1} + w(l_1,r_1) \\ f_{l_2,r_2} \leq g_{v,l_2,r_2} &= f_{l_2,v} + f_{v+1,r_2} + w(l_2,r_2) \end{aligned} 再由
u+1 \leq v+1 \leq r_1 \leq r_2 f_{u+1,r_1} + f_{v+1,r_2} \leq f_{u+1,r_2} + f_{v+1,r_1} 将前两个不等式累加,并将第三个不等式代入,可得
\begin{aligned} f_{l_1,r_1} + f_{l_2,r_2} & \leq f_{l_1,u} + f_{l_2,v} + f_{u+1,r_1} + f_{v+1,r_2} + w(l_1,r_1) + w(l_2,r_2) \\ & \leq g_{u,l_1,r_2} + g_{v,l_2,r_1} = f_{l_1,r_2} + f_{l_2,r_1} \end{aligned} -
若
v< u l_1\leq v<r_1,l_2\leq u<r_2 \begin{aligned} f_{l_1,r_1} \leq g_{v,l_1,r_1} &= f_{l_1,v} + f_{v+1,r_1} + w(l_1,r_1) \\ f_{l_2,r_2} \leq g_{u,l_2,r_2} &= f_{l_2,u} + f_{u+1,r_2} + w(l_2,r_2) \end{aligned} 再由
l_1 \leq l_2 \leq v \leq u f_{l_1,v} + f_{l_2,u} \leq f_{l_1,u} + f_{l_2,v} 将前两个不等式累加,并将第三个不等式代入,可得
\begin{aligned} f_{l_1,r_1} + f_{l_2,r_2} & \leq f_{l_1,u} + f_{l_2,v} + f_{v+1,r_1} + f_{u+1,r_2} + w(l_1,r_2) + w(l_2,r_1) \\ & \leq g_{u,l_1,r_2} + g_{v,l_2,r_1} = f_{l_1,r_2} + f_{l_2,r_1} \end{aligned}
-
综上所述,两种情形均有
定理 1:若状态
记
-
若
k_1>u u+1 \leq k_1+1 \leq r-1 \leq r f_{u+1,r-1} + f_{k_1+1,r} \leq f_{u+1,r} + f_{k_1+1,r-1} 再根据
u f_{l,r} f_{l,u} + f_{u+1,r} \leq f_{l,k_1} + f_{k_1+1, r} 将以上两个不等式相加,得
f_{l,u} + f_{u+1,r-1} \leq f_{l,k_1}+f_{k_1+1,r-1} 即
g_{u,l,r-1} \leq g_{k_1,l,r-1} k_1 k_1\leq u -
若
u>k_2 l\leq l+1 \leq k_2\leq u f_{l,k_2} + f_{l+1,u} \leq f_{l,u} + f_{l+1, k_2} 再根据
k_2 f_{l+1, r} f_{l+1,k_2} + f_{k_2+1, r} \leq f_{l+1,u} + f_{u+1,r} 将以上两个不等式相加,得
f_{l,k_2}+f_{k_2+1,r} \leq f_{l,u} + f_{u+1,r} 即
g_{k_2,l,r} \leq g_{u,l,r} u u \leq k_2
因此,如果在计算状态
核心代码
1 2 3 4 5 6 7 8 9 10 11 | // 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 问题有着如下的形式:
总共有
实际上此形式也有同样的结论,可以在
复杂度解决,读者可以模仿 2D1D 类似的给出证明。 O(n m)
令
我们可以更有效地解出所有状态。假设我们对于固定的
为了最小化运行时间,我们便需要应用分治法背后的思想。首先计算
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 动态规划中的情形不同,在这里我们根据决策单调性只能得出每次枚举
先考虑一种简单的情况,转移函数的值在动态规划前就已完全确定。即如下所示状态转移方程:
在这种情况下,我们定义过程
代码实现
1 2 3 4 5 6 7 8 9 10 11 | // 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)
|
使用递归树的方法,容易分析出该分治算法的复杂度为
「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。
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:Marcythm, zyf0726, hsfzLZH1, MingqiHuang, Ir1d, greyqz, billchenchina, Chrogeek, StudyingFather
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用