# 1. 线性规划基础
可以根据条件列出一个不等式区间,然后根据目标函数来判断极值位于哪里
比如 lec 中的例题
目标函数:最大化形式 f (x,y)=200,000x+250,000yf (x, y) = 200,000x + 250,000yf (x,y)=200,000x+250,000y。
约束条件来自资源限制(如砖块、门、窗):
10,000x+8,000y≤168,000
4x+2y≤60
5x+10y≤150
x≥0,y≥0
示意图:
这个点通过平移 k=-0.8 的线找到的最大交点。
这样类型的情况一般有四种
- 单一解,即最大值情况只会在某一个点达到
- 无解,比如同时存在 x<1 和 x>2
- 解不唯一,比如 f (x,y) 函数与某一个界定条件的边的斜率相同时,整条边都是最优解
- 无界,比如 c 向量的方向和界域的开口方向相同
# 2. 增量算法
# 🧩 增量算法的核心思想
我们有很多线性约束(比如 h1,h2,...,hnh_1, h_2, ..., h_nh1,h2,...,hn),它们构成一个凸多边形的可行域。我们希望找到在这个区域中,使目标函数最大的那个点。
而增量算法的思路是:
一条条逐个加入约束,每次更新当前最优解。
# 🪜 增量算法流程(二维情况)
# ✅ 初始化
先人为地加入两个 “大” 的边界(例如 x≤Mx \leq Mx≤M, y≤My \leq My≤M,用于限制区域),形成初始的区域 F0F_0F0。
- 通常从一个初始的角点 v0v_0v0 开始(比如可行域的右上角)
# ✅ 增量地加入约束
对于第 iii 条约束 hih_ihi,我们查看:
如果当前最优点 vi−1v_{i-1} vi−1 仍满足新的约束 hih_ihi
→ 不用更新,直接设 vi=vi−1v_i = v_{i-1} vi=vi−1如果 vi−1v_{i-1} vi−1 不满足 hih_ihi
→ 新可行区域被切掉了,必须重新计算新的最优点 viv_ivi,这个点一定在 hih_ihi 的边界上
这个操作在二维中很快,因为边界是线段,交点很容易计算。
# 🔁 重复这一过程
直到所有 nnn 个约束都处理完毕,最终的 vnv_nvn 就是目标函数的最大值点。
# 📈 时间复杂度
每一步最坏需要重新计算一次最优点,最多耗费 O (i) 时间
总的复杂度是:
# 🎲 改进版:随机增量算法(Random Incremental Algorithm)
如果我们随机打乱约束的顺序再增量处理,期望复杂度可以降到 O (n)
核心思想是:大多数情况下,新的约束不会改变当前最优解
通过 “后向分析(backward analysis)” 可以证明其期望复杂度为 O (n)
定义随机变量 XiX_iXi 表示第 iii 次加约束时,是否需要 “重新计算”:
Xi=0 → 如果 vi−1∈hi,不需要更新
Xi=1 → 如果 vi−1∉hi,需要重新找最优解
那么第 iii 步的耗时为:O (i)・Xi
加上初始常数时间,总的运行时间是:
我们用期望的线性性:
在随机顺序下,第 iii 步 “需要重新计算” 的概率 \mathbb{E}[X_i] \leq \frac{2}
所以代入总和:
关于这个部分是如何推导出来的,我们可以参考后向分析 (backward analysis)
因为每个 vi 都是两个 hi 的交点,故假设把这两个 hi 放回未分配的 h 集合当中,那么当添加 hi 时会导致最优点为 vi 的概率就为 2/i。
# 🧠 举个例子理解
假设一开始你有一个三角形的可行域,你的目标是找右上角的点(比如利润最大)。如果你突然加入一个 “新约束”—— 在这个三角形上面画一条线往下压,如果原来的最优点还在这条线的下方(满足约束),你啥都不用改;但如果不满足,那你只能重新在新交点里找最大值点。
# 3. 最小包围圆问题
给定一个平面上的点集 P={p1,p2,...,pn} P = {p_1, p_2, ..., p_n} P={p1,p2,...,pn},我们要找到:
一个圆,它包含所有点,且半径最小。
这个圆叫做最小包围圆(Minimum Enclosing Disk, 简称 MED)。
# 🧠 有哪些性质?
这个圆是唯一的。
最小包围圆的边界上最多有三个点(想想三点确定一个圆)。
实际上,它的边界上一定有至少两个点,否则可以缩小圆。
# 🚶♂️ 我们怎么找到这个圆?
我们可以用一种叫 Welzl’s 随机增量算法,它的思路和线性规划中的随机增量算法非常类似,而且 ** 期望时间复杂度是 O (n)
# 🔁 算法步骤(简化版)
我们记一个辅助函数:
MinDisk(P, R)
PPP:还没处理完的点集
RRR:已知在圆边界上的点(最多 3 个)
目标是找一个包含所有 PPP 的最小圆,且边界包含所有 RRR 中的点
# ▶ 主函数: MinDisk(P)
随机打乱点集 PPP
从前两个点开始构造一个初始圆
依次加入点 pip_ipi,检查是否在当前圆 Di−1D_{i-1} Di−1 内:
✅ 是:跳过
❌ 否:那么 pip_ipi 一定在最小圆边界上 ⇒ 递归调用
MinDiskWith1Pt(P[1..i-1], p_i)
# ▶ 辅助函数: MinDiskWith1Pt(P', p_i)
给定点 pi 一定在圆的边界上:
对 P′做随机排列
从 pi 和第一个不在圆里的点 pj 开始构造一个新的圆
如果有点 pk 仍在圆外 ⇒ 调用
MinDiskWith2Pts(P[1..j-1], p_i, p_j)
# ▶ 辅助函数: MinDiskWith2Pts(P', p_i, p_j)
这时候我们已经知道 pi 和 pj 都必须在圆上:
找到一个包含 pi,pj 且也包含 P′ 的最小圆
如果还有点不在圆里,说明它也必须在圆的边界上 ⇒ 用这三个点直接构造外接圆(三点定圆)
# ⏱ 复杂度分析
每个点最多只会触发常数次递归
所以算法的 期望时间复杂度是 O (n)
# 4. 带约束违反的线性规划
# 📌 什么是 “带约束违反” 的线性规划?
标准的线性规划要求所有约束都必须满足:
Maximize f(x)=cTxsubject to Ax≤b\textMaximize } f(x) = cAx \leq bMaximize f(x)=cTxsubject to Ax≤b
但是现实中很多问题可能:
有一些约束 很严格,稍微放松一点效果可能更好
或者数据本身就有误差、冲突,无解
所以我们允许最多违反 kkk 条约束,这样就变成了:
找一个解,使目标函数最大,同时最多违反 kkk 个约束。
这类问题称为:
Linear Programming with Violations\textbf{Linear Programming with Violations}Linear Programming with Violations
# 🧠 举个例子帮助理解:
你是工厂老板,有 10 条资源限制(约束),但你愿意 “睁一只眼闭一只眼”,允许最多放宽 2 条,这样可能整体利润更高。
# 📏 问题形式化(from 讲义)
原始线性规划有 n 条约束(不等式)
我们现在允许最多扔掉 k 条约束
目标是:找到一个满足其余 n−k 条约束的最优解
# ❗问题难点:
你可以想象,暴力枚举 “扔掉哪 kkk 条” 要试很多种:
总共有 种组合
每种组合要解一次线性规划(假设可以在线性时间里解决)
那么总时间就是:
太慢了!
# ✅ 怎么办?引入随机化算法
讲义里介绍了一种非常聪明的方法:
# 🎲 随机算法流程(核心思想):
重复执行 M 次,每次:
以概率 从原始约束中随机挑出一个子集 L′
解这个子集构成的线性规划
如果这个解只违反了最多 k 条原约束,就记录它
最后取这些尝试中 “最好” 的解作为结果
# ✅ 算法优势:
虽然一次尝试成功的概率不高,但我们可以多试几次 —— 就像买彩票,买得够多,总能中大奖。
通过分析可知,只要我们重复:
次尝试,就能以至少 的概率找到最优解。
# 📈 最终复杂度:
比暴力 快很多!
# 🔚 总结一句话:
“带约束违反” 的线性规划,就是允许你最多扔掉 kkk 条限制来找最优解。虽然暴力方法慢,但可以通过随机算法在线性时间内高概率找到最优解,特别适合约束很多、但你只想放松一小部分的场景。