当前位置:首页 > 技术 > 正文内容

深入解析四边形不等式与一维动态规划决策单调性优化

访客 技术 2026年7月13日 7

四边形不等式的数学定义与核心性质

在算法设计与优化中,四边形不等式是证明动态规划决策单调性的重要数学工具。对于定义在整数域上的二维函数 \(W(i, j)\),若对于任意满足 \(a \leq b \leq c \leq d\) 的整数,均成立以下不等式:

\[ W(a, d) + W(b, c) \geq W(a, c) + W(b, d) \]

则称函数 \(W\) 满足四边形不等式。

核心性质与证明

在实际应用中,直接验证上述定义往往较为繁琐。我们可以通过一个更弱的局部条件来推导全局性质:若对于任意相邻的整数 \(i < j\),满足:

\[ W(i, j+1) + W(i+1, j) \geq W(i, j) + W(i+1, j+1) \quad \text{①} \]

那么 \(W\) 必然满足四边形不等式。

证明过程:

首先,固定 \(j\),对 \(i\) 进行累加。取 \(i+1 < i+2 \leq j < j+1\),令 \(i' = i+1\),代入条件 ① 可得:

\[ W(i+1, j+1) + W(i+2, j) \geq W(i+1, j) + W(i+2, j+1) \quad \text{②} \]

将 ① 与 ② 相加,消去中间项 \(W(i+1, j+1)\) 和 \(W(i+1, j)\),整理后得到:

\[ W(i, j+1) + W(i+2, j) \geq W(i, j) + W(i+2, j+1) \]

通过数学归纳法不断累加,可推广至任意 \(a \leq b\),即:

\[ W(a, j+1) + W(b, j) \geq W(a, j) + W(b, j+1) \quad \text{③} \]

接下来,固定 \(a\) 和 \(b\),对 \(j\) 进行累加。取 \(a \leq b \leq c+1 < c+2\),由 ③ 可得:

\[ W(a, c+2) + W(b, c+1) \geq W(a, c+1) + W(b, c+2) \quad \text{④} \]

将 ③ 与 ④ 相加并消去中间项,整理得到:

\[ W(a, c+2) + W(b, c) \geq W(a, c) + W(b, c+2) \]

同理,通过归纳法可将右端点推广至任意 \(d \geq c\),最终证得对于任意 \(a \leq b \leq c \leq d\),均有 \(W(a, d) + W(b, c) \geq W(a, c) + W(b, d)\)。

该不等式之所以被称为"四边形不等式",是因为其几何直观可以映射为四边形边长与对角线的关系,如下图所示:

四边形不等式几何直观

在特定的几何构造中,该式等价于证明 \(AD + BC \geq AC + BD\)。

动态规划中的决策单调性优化

考虑一类常见的一维动态规划模型(1D1D DP),其状态转移方程为:

\[ f(i) = \min_{0 \leq j < i} \{ f(j) + w(j, i) \} \]

此类方程通常出现在区间划分问题中:将 \(n\) 个元素划分为若干连续段,\(w(j, i)\) 表示区间 \((j, i]\) 的代价,目标是求最小总代价。朴素解法的时间复杂度为 \(\mathcal{O}(n^2)\)。

定义 \(p(i)\) 为状态 \(i\) 的最优决策点,即使得 \(f(j) + w(j, i)\) 取最小值的 \(j\)。若代价函数 \(w\) 满足四边形不等式,则可以利用决策单调性将复杂度优化至 \(\mathcal{O}(n \log n)\)。

决策单调性定理

性质 1: 若 \(w\) 满足四边形不等式,则最优决策点 \(p(i)\) 随 \(i\) 单调不减,即 \(p(i) \leq p(i+1)\)。

性质 2: 若存在 \(x < j\),且对于某个 \(i > j\),决策 \(j\) 优于决策 \(x\)(即 \(f(j) + w(j, i) \leq f(x) + w(x, i)\)),则对于所有 \(i' > i\),决策 \(j\) 依然优于 \(x\)。

证明:

由已知条件 \(f(j) + w(j, i) \leq f(x) + w(x, i)\),且 \(w\) 满足四边形不等式(注意 \(x < j \leq i < i'\)):

\[ w(x, i') + w(j, i) \geq w(x, i) + w(j, i') \]

移项可得:

\[ w(j, i') - w(j, i) \leq w(x, i') - w(x, i) \]

将此式与已知不等式相加,即可得到 \(f(j) + w(j, i') \leq f(x) + w(x, i')\),证明完毕。

算法实现:单调队列与二分查找

基于上述性质,每个决策点 \(j\) 能够优化的状态 \(i\) 构成一个连续的右半区间 \([L_j, n]\)。我们可以维护一个单调队列,队列中的每个元素是一个三元组 \((l, r, c)\),表示在状态区间 \([l, r]\) 内,最优决策点均为 \(c\)。

当计算完 \(f(i)\) 并准备将 \(i\) 作为新决策点加入队列时,我们从队尾开始检查。若 \(i\) 在队尾区间的左端点优于原决策点,则直接弹出队尾;若在右端点优于原决策点,则通过二分查找确定新旧决策点的分界位置,截断原区间并将新三元组入队。此方法可将均摊时间复杂度降至 \(\mathcal{O}(n \log n)\)。此外,该模型也可通过分治法实现同等复杂度的优化。

经典算法实战:玩具装箱问题

以 P3195 [HNOI2008] 玩具装箱为例。设 \(f(i)\) 为前 \(i\) 个玩具的最小费用,\(S(i)\) 为前缀和。转移方程为:

\[ f(i) = \min_{0 \leq j < i} \{ f(j) + (S(i) - S(j) + i - j - 1 - L)^2 \} \]

令 \(X(i) = S(i) + i\),\(C = L + 1\),则代价函数 \(w(j, i) = (X(i) - X(j) - C)^2\)。

四边形不等式证明:

设 \(Q = S(i) - S(j) - 1 - L\),则 \(w(j, i) = Q^2\)。展开交叉项与包含项的差值:

\[ w(j, i) + w(j+1, i+1) - w(j+1, i) - w(j, i+1) = -2(C_{i+1}+1)(C_{j+1}+1) \]

由于玩具长度 \(C \geq 1\),该差值恒小于等于 \(-8\),即严格满足 \(w(j, i) + w(j+1, i+1) \leq w(j+1, i) + w(j, i+1)\),证明其具备决策单调性(本题更常见的解法是将其转化为斜率优化)。

#include <iostream>
#include <vector>

using namespace std;
using ll = long long;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    ll L;
    if (!(cin >> n >> L)) return 0;

    vector<ll> prefix(n + 1, 0);
    vector<ll> X(n + 1, 0); 
    vector<ll> Y(n + 1, 0); 
    vector<ll> dp(n + 1, 0);

    for (int i = 1; i <= n; ++i) {
        ll c;
        cin >> c;
        prefix[i] = prefix[i - 1] + c;
        X[i] = prefix[i] + i;
        Y[i] = (X[i] + L + 1) * (X[i] + L + 1);
    }
    Y[0] = (L + 1) * (L + 1);

    vector<int> q(n + 1);
    int head = 0, tail = 0;
    q[tail++] = 0;

    auto slope = [&](int j1, int j2) -> double {
        return (double)(dp[j2] + Y[j2] - dp[j1] - Y[j1]) / (X[j2] - X[j1]);
    };

    for (int i = 1; i <= n; ++i) {
        while (head + 1 < tail && slope(q[head], q[head + 1]) <= 2.0 * X[i]) {
            head++;
        }
        int best_j = q[head];
        dp[i] = dp[best_j] + (X[i] - X[best_j] - L - 1) * (X[i] - X[best_j] - L - 1);

        while (head + 1 < tail && slope(q[tail - 2], q[tail - 1]) >= slope(q[tail - 1], i)) {
            tail--;
        }
        q[tail++] = i;
    }

    cout << dp[n] << "\n";
    return 0;
}

经典算法实战:诗人小G问题

P1912 [NOI2009] 诗人小G 的状态转移方程为:

\[ f(i) = \min_{0 \leq j < i} \{ f(j) + |S(i) - S(j) + i - j - 1 - L|^P \} \]

为证明其决策单调性,需验证 \(G_j(i) = |S(i) + i - (S(j) + j) - (1 + L)|^P\) 满足四边形不等式。通过变量代换,问题等价于证明函数 \(h(x) = |x|^P - |x+z|^P\) (其中 \(z \geq 0\))在定义域内单调递减。

通过分类讨论 \(x\) 的正负及 \(P\) 的奇偶性,对 \(h(x)\) 求导可得 \(h'(x) \leq 0\) 恒成立,从而严格证明了其满足四边形不等式。因此,可直接应用单调队列结合二分查找的 \(\mathcal{O}(n \log n)\) 算法。

#include <iostream>
#include <vector>
#include <string>
#include <cmath>

using namespace std;
using ld = long double;

struct Segment {
    int opt, left, right;
};

int n, L, P;
vector<int> len_sum;
vector<ld> dp;
vector<int> opt_from;
vector<Segment> q;
int head, tail;

ld calc_cost(int j, int i) {
    ld base = abs(len_sum[i] - len_sum[j] + i - j - 1 - L);
    ld res = 1.0;
    for (int k = 0; k < P; ++k) res *= base;
    return dp[j] + res;
}

void add_decision(int i) {
    int pos = n + 1;
    while (head <= tail && calc_cost(q[tail].opt, q[tail].left) >= calc_cost(i, q[tail].left)) {
        pos = q[tail--].left;
    }
    if (head <= tail && calc_cost(q[tail].opt, q[tail].right) >= calc_cost(i, q[tail].right)) {
        int l = q[tail].left, r = q[tail].right;
        while (l < r) {
            int mid = l + (r - l) / 2;
            if (calc_cost(q[tail].opt, mid) >= calc_cost(i, mid)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        q[tail].right = r - 1;
        pos = r;
    }
    if (pos <= n) {
        q[++tail] = {i, pos, n};
    }
}

void solve() {
    cin >> n >> L >> P;
    vector<string> words(n + 1);
    len_sum.assign(n + 1, 0);
    dp.assign(n + 1, 0);
    opt_from.assign(n + 1, 0);
    q.assign(n + 2, {0, 0, 0});
    
    for (int i = n; i >= 1; --i) {
        cin >> words[i];
    }
    for (int i = 1; i <= n; ++i) {
        len_sum[i] = len_sum[i - 1] + words[i].length();
    }

    head = 0; tail = 0;
    q[0] = {0, 1, n};

    for (int i = 1; i <= n; ++i) {
        dp[i] = calc_cost(q[head].opt, i);
        opt_from[i] = q[head].opt;
        if (q[head].right == i) head++;
        q[head].left = i + 1;
        add_decision(i);
    }

    if (dp[n] > 1e18) {
        cout << "Too hard to arrange\n";
    } else {
        cout << (long long)dp[n] << "\n";
        for (int i = n; i > 0; i = opt_from[i]) {
            for (int j = i; j > opt_from[i]; --j) {
                cout << words[j];
                if (j != opt_from[i] + 1) cout << " ";
            }
            cout << "\n";
        }
    }
    cout << "--------------------\n";
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    if (cin >> T) {
        while (T--) solve();
    }
    return 0;
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。