线性规划 1
推荐阅读:
https://www.cnblogs.com/frankkk/p/9179190.html
https://zhuanlan.zhihu.com/p/31644892
https://blunt-axe.gitee.io/2020/02/19/20200219-LP-Duality/
写到一半突然看到 dxm 的 2021 论文,所以也可以把这篇当作阅读随笔。当然两边的编排不是很一样,我可能之后会再看看那个。
写到最后突然看到 zxy 的 2016 论文,所以也可以把这篇当作阅读随笔。当然两边的编排不是很一样,我可能之后会再看看那个。
如果出现数学符号无法渲染的情况请多刷新几遍。
线性规划()是一类最优化问题,这类问题的约束条件和目标函数均是线性的。下文中将使用大量线性代数的语言。
一般地,我们使用斜粗体 记向量,用斜体 表示 中第 维的值。 当且仅当 。记 表示 维实向量组成的空间。
1 形式
首先介绍线性规划的标准形式。
(线性规划的标准形式)
设 。以下问题被称作线性规划的标准形式:
需要优化的目标函数为 ,其对应的解为 。约束条件为 。我们将满足约束条件的解称作可行解,其全体称作可行域。可行解中满足最大化目标函数的解称作最优解 ,此时目标函数的值称为此线性规划问题的值。习惯上一个线性规划问题的代号同样指代该问题的值。
所有线性规划问题都可以被表示为标准形式。同时,线性规划有一种松弛形式,其利于几何分析与施单纯形法求解。这时我们需要满足 。
我们可以发现, 的解定满足 。因此可以等价地将标准形改写成
随后可以通过适当地变号( 第 行变号)使得定满足 。因此有与标准形式等价的松弛形式:
(线性规划的松弛形式)
这样可以轻易地确定一组可行解,即 。
基本形式就介绍到这里,接下来我们考虑如何求解线性规划问题。
2 求解
2.1 基础内容讨论
考虑 是一个 的矩阵,。我们将 中的列向量重新排序,以期得到更好的性质。具体地,我们提取 中 个线性无关的列向量组成一个方阵 ,将剩余的向量组成一个 的矩阵 。 可以被写作分块矩阵 的形式。我们称 为一个基,其中的列向量称作基本列向量。
矩阵 非奇异,因此 的一组解 的前 个元素对应了 ,其余元素为 。我们称这样的 为 的一组基解,其元素 称作基变量。可以发现基解的数量最多是 个。满足 的解被称作基可行解。
此时有 。由于矩阵 非奇异,。此时若将 按 分块为 ,目标函数值即为 。
可以发现,可行域一定对应 内的一个凸集(或空集),且每个基可行解总对应这个凸集的一个角点。感性理解
同时,最优解一定对应着一个基可行解。
我们求解答案的算法可以首先确定一个角点,随后一步步转移到最优解对应的角点。这就是单纯形法。
2.2 单纯形法
总的来说,单纯形法分为三个部分,我们需要回答以下问题:
- 如何从一个角点转移到相邻的角点?
- 如何确定该转移到哪个角点?
- 什么时候才能停止转移?即,如何判断当前解是最优解?
假设当前的约束矩阵 ,已经得到了一组基可行解 。 对应的一组基变量为 ,基本列向量为 。
由于 非奇异,其定能表出任意 大小的向量。从 中取出一个向量 ,则这个列向量可以由 的线性组合表出。即 。我们令
我们称 为出基变量, 为入基变量;对应的列向量被称作出/入基向量。我们将使用所求值构造新解。
我们令 为基 对应的一组解,其中 ( 是入基变量的系数)。由于 ,且 ,因此 为一组新的可行解。
但是问题又来了,该如何选择入基向量才能使得答案变化最大呢?
若现在的一组解是 ,目标函数的值为 。我们新选取的可行解是 ,其同样满足 ,即 。则新可行解
我们现在只需要看两解的差值即可。
记 。能发现,选择一个非基变量 ,会让结果变化 。,这时若有 ,就能确定一个更优的解 。我们希望每次选择的值是最优的,因此每次都选择 。
我们将 称作判别数。选择新角点的关键是首先求出非基变量的判别数,从其中选取最小的负值,其对应的非基变量就是新的入基变量。
这也自然地导出了最优解:当一个角点处所有判别数均非负时,这个角点无法转移到更大的值处,因此其取得了最大值。
讲到这里,我们就能发现先前提到的松弛形式的意义了。松弛形式引入了数个人工变量 ,从而能快速构造出一组初始解,方便单纯形法求解。
我们还能发现,若原线性规划问题有解 ,对于松弛形式,只有当 时才能得到最优解。
有时可行域是无界的,这时可能取到一个无穷大的解,此时称该线性规划问题的解为无界解。由于在实际问题中不可能取到无穷大,因此无界解通常表明问题的形式有误。
在单纯形法中,无界解等价于 。
关于单纯形法的复杂度,可以参阅以下两篇论文:
- Smoothed Analysis of Algorithms: Why the Simplex Algorithm Usually Takes Polynomial Time?, Daniel A. Spielman, Shang-Hua Teng, 2001
- A Randomized Polynomial-Time Simplex Algorithm for Linear Programming, Jonathan A. Kelner, Daniel A. Spielman, 2006
可以相信在绝大多数情况下,单纯形算法都可以处理 的数据。
只应用单纯形法有时无法解决问题,我们需要借助其他方法将问题转化。
3 对偶法
一个常用的方法是对偶。
3.1 对偶的基础应用
首先给出对偶问题的定义:
(线性规划的对偶)
给出一个线性规划的如定义 的标准形式,其称为原问题(下文称 或 )。以下问题则称为 的对偶(下文称 或 ):
容易验证 。因此一个线性规划标准形的对偶也是标准形。
写出一般图最大匹配对应的 形式,以及 。说明 的意义。
设图 的关联矩阵 。令 表示取边集 函数(即 )。注意 不是邻接矩阵。
考虑约束 。这表示 取到的边集同 中每个点至多有一次邻接,即一个匹配。目标函数可以写作 ,也就是最大匹配数。有标准形式
带权图则可以将 转化为 。
同样地,我们可以写出对偶
这时 表示了取点集 函数(即 )。此时约束表示了 中每一条边都至少与 中一个顶点相邻,最小化目标函数即找到最小的满足条件的点集大小。
这使我们想到了点覆盖。可以发现,最大匹配的对偶问题是最小点覆盖问题。
3.2 对偶性
在上面的问题中,我们发现自变量的取值范围仅为整数。这比一般线性规划的要求高。如果线性规划问题中 的元素都是整数,则我们称该问题为整数线性规划()。
需要注意的是,求解一般的整数线性规划问题是 问题。对于特殊问题,如二分图的匹配,最优解一定对应着一组整数解,因此可以视作普通线性规划求解。
具体地, 的所有基本解均为整数向量当且仅当 为一全幺模矩阵。因此当约束矩阵是全幺模矩阵时,整数线性规划可以与普通线性规划同方式求解。
对于对偶问题,有以下定理。
(弱对偶性)
设线性规划的原问题和对偶如定义 形式,记为 。 的值不大于 的值。特别地,如果 分别为 的可行解,且满足 ,则 分别为 的最优解。
证明:
由这个可以引出一般图最大匹配不大于最小点覆盖。可以证明在二分图中最大匹配等于最小点覆盖,而这需要应用强对偶性。证明见此。
(强对偶性)
设线性规划的原问题和对偶如定义 形式,记为 。下面的叙述有且仅有一个成立:
- 均有最优解,且 。
- 有可行解, 无可行解,且 的目标函数在约束条件下无界。
- 有可行解, 无可行解,且 的目标函数在约束条件下无界。
- 均无可行解。
我们若想计算原问题的最优解,很多情况下就可以转化为计算对偶问题的最优解。
求解带权二分图最大权匹配。
我们设左右各 个点的二分图 的关联矩阵为 ,边权为 。我们需要找出一个完美匹配使得边集中包含的边权和最大。
仍然考虑 代表取边集函数。写出 :
转对偶:
容易发现这就是 KM 算法所模拟的过程,其最终也最小化了顶标和。因此应用 KM 算法即可。
3.3 流模型的应用
浅析最大费用循环流模型。
首先我们需要解决一个问题。假设题目信息被抽象为了一个线性规划问题,但是其要求并不只是各维满足 ,还要求在特定维上满足 。如何解决?
假设这一维描述为 。则我们可以将其视为 。假设这两个限制对偶后对应的变量是 ,则我们需要最小化 。虽然有限制 ,但是可以发现 不一定 。因此不拆开的限制对偶后对应的变量 是没有限制的,其 。
同样的,如果原问题中存在 的变量,对偶后对应的限制就应当取等。
然后定义最大费用循环流模型:循环流是无源汇的流,满足每个节点流量守恒。给定一张流网络,容量为 ,费用为 。求一个循环流 ,最大化 。
最大费用循环流可以通过网络流的方式求解,具体看无源汇最大费用可行流。
问题写作线性规划形式即为
转对偶。假设第一个限制条件对应的变量为 ,第二个限制条件对应的变量为 ,有
容易发现 时最优。因此最大费用循环流的目标就是最小化
因此我们可以将一个问题转化为最小化上式,随后利用网络流求解。
浅析最小费用流模型。
给定一张流网络,容量为 ,费用为 , 为 点的流出量(出流量 入流量 )。求一个流 ,最小化 。
令 为 的变量, 为需求变量。转对偶有
也就是说我们需要 个 , 个 , 个 。
整理可得我们需要最小化
这样遇到类似于最小化这类式子的题就可以采用单纯形法做了。
4 例题
战线可以看作一个长度为 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第 号位置上建一座塔有 的花费,且一个位置可以建任意多的塔,费用累加计算。有 个区间 ,在第 个区间的范围内要建至少 座塔。求最少花费。
。
考虑设 为塔数量的向量, 为花费向量, 为建塔数量向量。构造矩阵 满足 。注意到 是全幺模矩阵,因此可以施单纯形法求解。
立即写出线性规划形式:
转对偶便于求解。
直接做即可。
单纯形法
怎么和我上面讲的单纯形法实现不一样?
#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
const int inf = 1e9;
const double eps = 1e-9;
int n, m, l, r;
namespace Simp {
const int N = 1e3 + 5, M = 1e4 + 5;
double A[N][M], c[N], d[M], res;
void pivot(int e, int l) {
double t = A[l][e];
c[l] /= A[l][e], t = A[l][e], A[l][e] = 1;
rep(i,1,m) if (i != e) A[l][i] /= t;
rep(i,1,n) if (i != l and fabs(A[i][e]) > eps) {
c[i] -= A[i][e] * c[l];
rep(p,1,m) if (p != e) A[i][p] -= A[i][e] * A[l][p];
A[i][e] = -A[i][e] * A[l][e];
} res += d[e] * c[l];
rep(i,1,m) if (i != e) d[i] -= d[e] * A[l][i];
d[e] = -d[e] * A[l][e];
}
double simplex() {
int j, k;
while (1) {
double mn = inf; k = 0;
for (j = 1; j <= m; ++ j) if (d[j] > eps) break;
if (j > m) return res;
rep(i,1,n) if (A[i][j] > eps and mn > c[i] / A[i][j])
k = i, mn = c[i] / A[i][j];
if (mn >= inf) return inf;
pivot(j, k);
} return res;
}
int calc() { return (int)(simplex() + 0.5); }
} // namespace Simplex_Method
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
rep(i,1,n) cin >> Simp::c[i];
rep(i,1,m) {
cin >> l >> r >> Simp::d[i];
rep(j,l,r) Simp::A[j][i] = 1;
} cout << Simp::calc() << '\n';
}
本题的另一种做法是应用最小费用流模型,将问题转化成最小费用最大流求解。
对建塔数作前缀和得到 ,得到线性规划模型
转化后面两个条件为 。可以通过与 取 约束取值范围。不难写出等价关系式
这就转化成最小费用流模型了。构图方式较明显。 连 的边, 连 的边,源点向 的点连 的边, 的点向汇点连 的边。最终费用取负值即可。
值得注意的是,该做法的实际复杂度远劣于单纯形法,在实际测试中得到了 70pts。
这也使得 UOJ487 中单纯形法变成了良好的优化,即网络单纯形法。可能在明天闲话里会谈到。
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/linear_programming_1.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具