线性规划学习笔记
线性规划学习笔记
〇、前言
本文是我对线性规划的一个整理。
主要参考了 zzq的博客 ,2016年国家集训队的两篇论文。
一、定义
1. 标准型线性规划
最大化 :
$$
\sum\limits_{i=1}^nc_ix_i
$$
$$
s.t. \sum\limits_{i=1}^n a_{j,i}x_i\le b_j,1\le j\le m
$$
$$
x_i\ge 0,1\le i\le n
$$
为了避免在求解过程中由于正负号带来的变换不等号问题,于是有了另一种表示方式——松弛型。
2. 松弛型线性规划
最大化
$$
\sum\limits_{i=1}^nc_ix_i
$$
$$
s.t. x_{i+n}=b_i-\sum\limits_{j=1}^n a_{i,j}x_j,1\le i\le m
$$
$$
x_j\ge 0,1\le j\le n+m
$$
二、求解——单纯形算法(Simplex algorithm)
求解范围:$b_i\ge0$
1. 定义
在松弛型等式左侧的变量我们成为 基变量。
在松弛型等式右侧的变量我们称为 非基变量。
线性规划中每一组限制都隐藏这一组基本解,对于 $x_{i+n}=b_i-\sum\limits_{j=1}^n a_{i,j}x_j,1\le i\le m$,有基本解 $x_{i+n}=b_i,x_j=0$。
2. 算法概述
单纯形算法有两个基本的操作 —— 转轴操作(Pivot) 和 **求解过程 (Simplex)**。
Pivot
转轴操作是对于一组限制中一个基变量 $x_A$ 和一个非基变量 $x_B$ 代换的操作。
我们称 $x_A$ 为换入变量,$x_B$ 为换出变量。
具体的说:
$$
x_{A}=b_i-\sum\limits_{j=1}^n a_{i,j}x_j
$$
把 $x_B$ 代换到等式左边,得:
$$
x_B=\dfrac{b_i-x_A-\sum\limits_{j=1,j\not = B}^na_{i,j}x_j}{a_{i,B}}
$$
当然在选择的时候要确保 $a_{i,B}\not= 0$。
用这条等式代替原等式,然后将这条等式依次带入其他等式和要优化的结果。
Simplex
Simplex 就是单纯形算法的主过程,从一个基本解出发,经过一系列的转轴操作,达到最优解。通过选择特定的换入变量和换出变量,使每一次转轴操作都能使目标函数增大,直到达到全局最优解。
基本过程:
- 选择一个满足 $c_e \ge 0$ 的非基变量 $x_e$。
- 找到那个满足 $a_{l,e} > 0$ 且 $\dfrac{b_l}{a_{l,e}}$ 最小的基变量 $x_{n+l}$。
- 执行 $pivot(l,e)$ 然后回到第一步。
每次选择一个增大后可以使当前状态变优的变量,将其增加到有一个基变量变成 $0$ 位置,然后互换他们的位置。
第二步取最小的目的是一个贪心优化,可以使 $pivot$ 的次数降低许多。
该过程在一下两种情况下会终止:
- 找不到一个合法的 $e$ ,显然现在已经找到了最优解。可以手模一组数据。
- 找不到一个合法的 $l$ ,此时的最优解是 $\infty$ 。
可能还是有点懵,我们拿论文里的例子模拟一下。
至于为什么是负号。如果看的仔细的话,前面线性规划的式子,每个 $a_{i,j}$ 之前都有个负号。
对于 $x_1$ ,显然在第三个限制 $\dfrac{b_3}{a_{3,1}}$ 最小。所以 $x_1$ 和 $x_6$ 互换位置,有了下边:
再对于 $x_3$ ,对于第 $2$ 条限制最小,$x_3$ 和 $x_5$ 互换位置。
对于 $x_2$ 也是同理。
现在,由于 $c_i< 0,1\le i\le n,x_i\ge 0$ ,显然 $x_3=x_5=x_6=0$ 原式有最大值。最大值就是 $28$。基变量的值就是 $b_i$ 。此时的最优解就是 $x={8,4,0,18,0,0}$。
单纯形算法的核心思想就是这样,把 $c_i\le 0$ ,使得所有的非基变量都为 $0$ 。这就解释了为什么只能把 $b_i$ 全部搞成正的,负的反而会使答案边小。
3. 初始化过程
前文提到了 $Simplex$ 只能在 $b_i\ge 0$ 的时候进行。如果 $b_i<0$ 呢?这时候就要进行初始化。
具体的,初始化常见的有两种方法:新建一个辅助线性规划或者通过 $pivot$ 进行初始化。本文只介绍后一种方法。
根据 $pivot$ 的过程,在 $a_{i,B}>0$ 的情况下,$b_i$ 的正负性并不会被改变。所以当 $b_i$ 为负数时,只需要找到一个 $a_{i,j}<0$ 进行转轴操作即可改变 $b_i$ 的正负性。
当然,如果 $b_i<0$ 时,并没有找到 $a_{i,j}<0$ ,此时整个线性规划无解。
三、实现
代码细节比较多。
对于我这种写法,$a_{i,j},i>0,j>0$ 一定要取相反数!
其中 $id_i$ 是指取第 $i$ 条限制基变量的原序号。
1 | const double eps=1e-8; |
四、对偶问题
给定一个原始线性规划:
最大化 :
$$
\sum\limits_{i=1}^nc_ix_i
$$
$$
s.t. \sum\limits_{i=1}^n a_{j,i}x_i\le b_j,1\le j\le m
$$
$$
x_i\ge 0,1\le i\le n
$$
定义它的对偶线性规划为:
最小化:
$$
\sum\limits_{j=1}^mb_jy_j
$$
$$
s.t.\sum\limits_{j=1}^m a_{i,j}y_j\ge c_i,1\le i\le n
$$
$$
y_j\ge 0,1\le j\le m
$$
其最优解相同。
五、例题
[NOI2008] 志愿者招募
设 $M_{i,j}$ 表示第 $i$ 类志愿者在第 $j$ 天能否工作,$x_i$ 表示第 $i$ 类志愿者的数量。
易列出原始线性规划:
最小化
$$
\sum\limits_{i=1}^m x_ic_i
$$
$$
s.t.\ \sum\limits_{i=1}^m M_{j,i}x_i\ge a_j ,1\le j\le m
$$
$$
x_i\ge 0,1\le i\le m
$$
转化为其对偶线性规划:
最大化
$$
\sum\limits_{j=1}^n y_ja_j
$$
$$
s.t.\ \sum\limits_{j=1}^n M_{i,j}y_j\le c_i,1\le i\le m
$$
$$
y_j\ge 0,1\le j\le n
$$
$Code:$
1 | signed main(){ |
[ZJOI2013]防守战线
板子
[SHOI2004]最小生成树
非常显然,树边不增,非树边不减。
考虑到非树边一定大于等于在最小生成树的路径上的边权,所以直接列约束条件。
注意到线性规划的一列只有两个非零值,非常浪费空间,所以用 $map$ 代替。
$$
d+\sum\limits_{i=1}^nc_ix_{id_i},id_i\in [1,n+m],c_i< 0
$$