专栏文章

别线性规划

算法·理论参与者 7已保存评论 7

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
7 条
当前快照
1 份
快照标识符
@mkr4owhz
此快照首次捕获于
2026/01/24 01:02
4 周前
此快照最后确认于
2026/02/19 01:15
11 小时前
查看原文

引入

线性规划是研究线性约束条件下线性目标函数最值的方法总称,如网络流等。OI 很少会出现只能用线性规划算法解决的问题,绝大多数这类问题可以通过网络流建模等方法更高效地解决。
举个例子:
你是一个工厂老板,仓库里有 10 吨木材8 个工时,你可以生产两种产品:椅子桌子
  • 做一把椅子:需 1 吨木材 + 2 个工时,利润 30 元
  • 做一张桌子:需 2 吨木材 + 1 个工时,利润 50 元
你的目标:决定生产多少椅子 (x1x_1) 和多少桌子 (x2x_2),使得总利润最大
把这个问题建模成 LP 就是:
Maximize Z=30x1+50x2(总利润)\begin{aligned} \text{Maximize } & Z = 30x_1 + 50x_2 \quad (\text{总利润}) \\ \end{aligned} s.t.1x1+2x210(木材限制)2x1+1x28(工时限制)x1,x20\begin{aligned} \text{s.t.} \quad & 1x_1 + 2x_2 \le 10 \quad (\text{木材限制}) \\ & 2x_1 + 1x_2 \le 8 \quad (\text{工时限制}) \\ & x_1, x_2 \ge 0 \end{aligned}
(此处忽略掉整数限制)
我们把这个东西画到平面上会发现一些性质:
  • 线性规划中的每个不等式约束都描述了一个半平面,所有可行解的集合就是半平面交,因此可行解的集合就是一个凸多边形。
  • 问题的最优解总可以取凸多边形的顶点
加上整数限制的 LP 问题是一类整数规划问题,而并非简单的线性规划问题(当然如果系数矩阵是全幺模矩阵,整数规划问题和线性规划问题是等价的,否则很多是 NP-Hard 的,比如背包)。

标准型

通常规定为:
maximizecTx\begin{aligned} \text{maximize} \quad & \mathbf{c}^T \mathbf{x} \\ \end{aligned} subject toAxbx0\begin{aligned}\text{subject to} \quad & \mathbf{A} \mathbf{x} \le \mathbf{b} \\ & \mathbf{x} \ge 0 \end{aligned}
三种要求:目标函数,约束条件和非负限制(单纯形法的基础)。
一些常用技巧:
  1. 添加负号转化最大最小问题和约束条件的方向。
  2. 等式约束拆成两个方向相反的约束。
  3. 如果变量没有正负数限制,将他替换成两个非负变量的差值。

对偶

原问题 (Primal)对偶问题 (Dual)
Maximize cTx\mathbf{c}^T \mathbf{x}Minimize bTy\mathbf{b}^T \mathbf{y}
Axb\mathbf{A} \mathbf{x} \le \mathbf{b}ATyc\mathbf{A}^T \mathbf{y} \ge \mathbf{c}
x0\mathbf{x} \ge 0y0\mathbf{y} \ge 0
AA 是约束条件的系数矩阵,xx 是解的列向量,bb 是约束条件的列向量,cc 是目标函数的系数列向量,ATA^T 表示 AA 的转置矩阵。
原问题转对偶问题的过程一共需要 3 步:
  1. 交换目标函数和约束符号的方向。
  2. 将约束条件的系数矩阵转置。
  3. 将原目标函数的系数列向量和原约束条件的列向量交换。

举个例子

将上面的例子作为原问题建模(为方便表示系数矩阵发生转置就把条件一 x2x_2 的系数改成 3):
Maximize Z=30x1+50x2(总利润)\begin{aligned} \text{Maximize } & Z = 30x_1 + 50x_2 \quad (\text{总利润}) \\ \end{aligned} s.t.1x1+3x210(木材限制)2x1+1x28(工时限制)x1,x20\begin{aligned} \text{s.t.} \quad & 1x_1 + 3x_2 \le 10 \quad (\text{木材限制}) \\ & 2x_1 + 1x_2 \le 8 \quad (\text{工时限制}) \\ & x_1, x_2 \ge 0 \end{aligned}
给问题对偶一下就变成了需要用最小代价收购木材和工时,单位木材和工时分别设置一个价格 y1y_1y2y_2,使得老板获得的利润不能低于他卖产品获得的利润,求出每个单位木材和工时的价格。
对偶问题建模:
Minimize W=10y1+8y2(总花费)\begin{aligned} \text{Minimize } & W = 10y_1 + 8y_2 \quad (\text{总花费}) \\ \end{aligned} s.t.1y1+2y230(椅子价格)3y1+1y250(桌子价格)y1,y20\begin{aligned} \text{s.t.} \quad & 1y_1 + 2y_2 \ge 30 \quad (\text{椅子价格}) \\ & 3y_1 + 1y_2 \ge 50 \quad (\text{桌子价格}) \\ & y_1, y_2 \ge 0 \end{aligned}

三大定理:

  1. 弱对偶定理 : cTxbTy \mathbf{c}^T \mathbf{x} \le \mathbf{b}^T \mathbf{y} 即:任意可行解的目标函数值,原问题(最大化) \le 对偶问题(最小化)。这为我们提供了上下界估算。
  2. 强对偶定理: 如果原问题和对偶问题都有界,原问题有最优解 xx^*,则对偶问题也有最优解 yy^*,且: cTx=bTy \mathbf{c}^T \mathbf{x}= \mathbf{b}^T \mathbf{y} 应用: 可以把最小化问题转化为最大化问题然后使用单纯形,或者原问题变量少,约束多,对偶完了就是变量多约束少。
  3. 互补松弛性 (Complementary Slackness): 一个可行解是最优解:对于原问题的第 ii 个约束,如果没取到等号(松弛了),则对偶变量 yiy_i 必须为 0,反之亦然。 (bAx)y=0 (\mathbf{b} - \mathbf{A}\mathbf{x}) \cdot y = 0 (cATy)x=0 (\mathbf{c} - \mathbf{A}^T\mathbf{y}) \cdot x = 0 应用: 原始对偶方法要用。 证明: 对任意可行解 x,yx,y,有 cxbyc^\top x \le b^\top y 考虑两者之差: bycx=ybxc=ybxAy+x(Ayc)=y(bAx)+x(Ayc)\begin{aligned} b^\top y - c^\top x &= y^\top b - x^\top c\\ &= y^\top b - x^\top A^\top y + x^\top(A^\top y - c) \\ &= y^\top(b - Ax) + x^\top(A^\top y - c) \end{aligned} 根据强对偶定理,两者之差为 0,又因为右边两项非负,所以推出互补松弛性。

原始-对偶方法

这个东西是解决线性规划问题的一类方法,最小费用最大流里面的 SSP 算法用的也是这个思想。
大体思路:先给出一个可行解,通过求解一系列相对简单的辅助问题,来逐步逼近原问题的最优解,对于原问题 Q1Q1
minimizecTx\begin{aligned} \text{minimize} \quad & \mathbf{c}^T \mathbf{x} \\ \end{aligned} subject toAxbx0\begin{aligned}\text{subject to} \quad & \mathbf{A} \mathbf{x} \ge \mathbf{b} \\ & \mathbf{x} \ge 0 \end{aligned}
将这个问题转化为对偶问题 Q2Q2
maximizebTy\begin{aligned} \text{maximize} \quad & \mathbf{b}^T \mathbf{y} \\ \end{aligned} subject toATycy0\begin{aligned}\text{subject to} \quad & \mathbf{A^T} \mathbf{y} \le \mathbf{c} \\ & \mathbf{y} \ge 0 \end{aligned}
根据互补松弛性,只需要找到一个可行解,使得 xT(ATyc)=0\mathbf{x^T} \mathbf{(A^Ty-c)} = 0,这个可行解就是最优解。
计算对偶问题紧约束的集合
I={i:(ATyc)i=0}I= \left\{i : (A^Ty-c)_i=0\right\}
那么原问题可以转化为问题 Q3Q3
minimize1Tz\begin{aligned} \text{minimize} \quad & \mathbf{1}^T \mathbf{z} \\ \end{aligned} subject toAx+z=bz0\begin{aligned}\text{subject to} \quad & \mathbf{A} \mathbf{x} + \mathbf{z} = \mathbf{b} \\ & \mathbf{z} \ge 0 \end{aligned}
  • xi0iIx_i \ge 0 \quad \forall i \in I
  • xi=0iIx_i = 0 \quad \forall i \notin I
如果问题 Q3 的最优解是 00,说明满足互补松弛性,此时的 xx 就是原问题最优解。
给问题 Q3Q3 对偶一下成问题 Q4Q4
maximizebTy\begin{aligned} \text{maximize} \quad & \mathbf{b}^T \mathbf{y} \\ \end{aligned} subject tojaji×yj0 iIbTy1\begin{aligned}\text{subject to} \quad & \sum_j a_{ji} \times y_j \le 0 \ \quad \forall i \in I& \\ \mathbf{b}^T \mathbf{y} \le 1 \end{aligned}
想办法利用 Q4Q4 的解改进 Q2Q2 的解,将问题 Q2Q2 的解 yQ2=yQ2+ϵyQ4y_{Q2} = y_{Q2}+\epsilon y_{Q4},在选取的 ϵ\epsilon 满足要求的情况下,yQ2y_{Q2} 一定是一组可行解,且目标函数值会更优。
选取 ϵ\epsilon 的具体方法式子推一推就行。
如果 ϵ=+\epsilon = +\infty,那么对偶问题无界,原问题不可解。

全幺模矩阵

这个东西可以判定判定这个线性规划问题的最优解是否是整数解,这样可以把整数规划问题转化为线性规划问题来求解。
矩阵 ARm×nA\in R^{m\times n} 称为全幺模(TU),当且仅当它的任意子矩阵(从 AA 中取同样行列数得到的方阵)的行列式都属于
det()0,1,1.\det(\cdot)\in{0, 1, -1}.
对于全幺模矩阵 AZm+n,bZm,CZnA \in Z^{m+n},b\in Z^m ,C\in Z^n 的线性规划问题
maximizecTx\begin{aligned} \text{maximize} \quad & \mathbf{c}^T \mathbf{x} \\ \end{aligned} subject toAxbx0\begin{aligned}\text{subject to} \quad & \mathbf{A} \mathbf{x} \le \mathbf{b} \\ & \mathbf{x} \ge 0 \end{aligned}
如果有界,最优解一定是整数解。
证明思路是:
  1. 先证明:当 AA TU 且 bb 整数时,xAxb{x\mid Ax\le b} 的所有极点都是整数
  2. 再用最优解可在极点取得的性质,因此存在整数最优解。
严谨证明参见:https://www.luogu.com.cn/paste/xi6i8dkm。
常见的图论模型中,网络流、最短路、二分图等对应的线性规划问题的系数矩阵都是全幺模矩阵。
一个引理是如果矩阵的每一列的 1 形成一个区间那么就是全幺模,当然给这个矩阵转置一下也成立。
严格证明需要使用 Ghouila–Houri 判据,这里不展开。

单纯形法

单纯形法的时间复杂度的渐进上界是 O(2nnm)O(2^n nm)O(2nm2)O(2^n m^2),其中 nn 是变量数,mm 是约束数,实际使用非常快,和网络流一样就是 O(能过)O(能过)
单纯形法主要是解决标准形式的线性规划问题:
max j=1ncjxjs.t. j=1naijxjbi (i=1..m), xj0\max\ \sum_{j=1}^n c_j x_j \quad \text{s.t. }\sum_{j=1}^n a_{ij}x_j \le b_i\ (i=1..m),\ x_j\ge 0
算法大体思路:
  1. 先将线性规划问题转化为标准形式,然后将 mm 个约束作为线性方程组求解(要求 rank A=m)。
  2. 然后对于每个线性方程添加松弛变量。
  3. 找到原问题的一组可行解,然后一直执行换基操作,直到最优解不再改进。

定义

把不等式变成等式:加松弛变量 si0s_i\ge 0
Ax+s=bAx + s = b
总变量数变成 n+mn+m。选出 mm 个变量当作基变量(它们对应的系数矩阵可逆),其余是非基变量。令非基变量全为 0,就能解出基变量的值——这就是一个基本解;若基变量也都 0\ge 0,就是基本可行解,对应一个顶点。
初始时如果 b0b\ge 0,基本可行解直接令非基变量全部为 0,基变量是 bb 即可。
否则需要两次单纯形先求出可行解。

换基操作

把当前状态理解成一组方程(把基变量用非基变量表示):
给定一个基 B=(B1,B2,,Bm)B=(B_1,B_2,\dots,B_m)(大小 mm)和非基 N=(N1,N2,,Nn)N=(N_1,N_2,\dots,N_n)(其余变量),把等式
ABxB+ANxN=bA_B x_B + A_N x_N=b
移项:
ABxB=bANxNA_B x_B = b - A_N x_N
则(由于最开始的保证 ABA_B 一定)
xB=AB1bAB1ANxNx_B = A_B^{-1}b - A_B^{-1}A_Nx_N
bˉ=AB1b,Aˉ=AB1AN\bar b = A_B^{-1}b,\qquad \bar A = A_B^{-1}A_N
那么:
xB=bˉAˉxN(D1)x_{B}=\bar b-\bar Ax_N \tag{D1}
目标函数
z=cBxB+cNxNz=c_B^\top x_B + c_N^\top x_N
代入 D1D1 得:
z=cBbˉ+(cNcBAB1AN)xNz=c_B^\top \bar b + \Big(c_N^\top - c_B^\top A_B^{-1}A_N\Big)x_N
z0=cBbˉ,cˉ=cNcBAˉz_0=c_B^\top\bar b,\qquad \bar c^\top= c_N^\top - c_B^\top \bar A
得到
z=z0+jNcˉjxj(D2)z = z_0 + \sum_{j\in N}\bar c_j x_j \tag{D2}
这里 cˉj\bar c_j 就是 检验数(在 max 下,cˉj>0\bar c_j>0 表示让 xjx_j 从 0 增大能让 zz 增大)。

1. 选入基变量

最大化问题里,如果存在某个非基变量 xjx_j 使 cˉj>0\bar c_j>0,说明增大它可以让 zz 变大 ⇒ 它是候选“入基”变量,选择入基变量有两种常用的好写的规则:
  1. 取检验数最大的那个(cˉj\bar c_j 最大的)。
  2. 取下标最小的那个(jj 最小的)。
第 1 种可能会循环但是效率高,第 2 种更稳定但是效率低。

2. 选出基变量

xex_e 增大时,基变量由 D1D1 变化:
xBi=bˉiaˉie,xex_{B_i} = \bar b_i - \bar a_{i e},x_e
为了保持可行性 xBi0x_{B_i}\ge 0,需要
  • 如果 aˉie>0\bar a_{ie}>0,则 xebˉi/aˉiex_e \le \bar b_i/\bar a_{ie}
  • 如果 aˉie0\bar a_{ie}\le 0,则这一行不对 xex_e 上界造成限制(增大 xex_e 不会让该基变量变负)。
所以可行域允许的最大步长是
xemini:aˉie>0bˉiaˉiex_e \le \min_{i:\bar a_{ie}>0}\frac{\bar b_i}{\bar a_{ie}}
取达到最小值的那一行 ll 作为出基变量 xBlx_{B_l}。这就是最小比值检验。
若所有 aˉie0\bar a_{ie}\le 0,则 xex_e 没上界,且 cˉe>0\bar c_e>0 会使 z+z\to+\infty,所以是 无界

3. pivot(换基)

设进基变量是 xeNx_e\in N,出基变量是 xBlx_{B_l}
从出基那一行 D1D1 取出:
xBl=bˉljNaˉljxjx_{B_l}=\bar b_l-\sum_{j\in N}\bar a_{lj}x_j
xex_e 单独拎出来:
xBl=bˉlaˉlexejNeaˉljxjx_{B_l}=\bar b_l-\bar a_{le}x_e-\sum_{j\in N\setminus{e}}\bar a_{lj}x_j
移项并除以 aˉle\bar a_{le}(注意 pivot 元要求 aˉle>0\bar a_{le}>0 才会被选为出基行):
xe=bˉlaˉle1aˉlexBljNeaˉljaˉlexj(P0)x_e=\frac{\bar b_l}{\bar a_{le}}-\frac{1}{\bar a_{le}}x_{B_l}-\sum_{j\in N\setminus{e}}\frac{\bar a_{lj}}{\bar a_{le}}x_j \tag{P0}
现在把 P0P0 代入所有其它行和目标行,使字典恢复成“基变量 = 常数 − 非基线性组合”的形式。
3.1 更新其它约束行 (il)(i\neq l)
原来第 ii 行:
xBi=bˉiaˉiexejNeaˉijxjx_{B_i}=\bar b_i-\bar a_{ie}x_e-\sum_{j\in N\setminus{e}}\bar a_{ij}x_j
代入 P0P0
xBi=bˉiaˉie(bˉlaˉle1aˉlexBljeaˉljaˉlexj)jeaˉijxj=(bˉiaˉiebˉlaˉle)bˉi(aˉie1aˉle)系数对 xBlxBlje(aˉijaˉieaˉljaˉle)aˉijxj\begin{aligned} x_{B_i} &=\bar b_i-\bar a_{ie}\Big(\frac{\bar b_l}{\bar a_{le}}-\frac{1}{\bar a_{le}}x_{B_l}-\sum_{j\neq e}\frac{\bar a_{lj}}{\bar a_{le}}x_j\Big) -\sum_{j\neq e}\bar a_{ij}x_j\\ &=\underbrace{\Big(\bar b_i-\bar a_{ie}\frac{\bar b_l}{\bar a_{le}}\Big)}_{\bar b'_i} -\underbrace{\Big(-\bar a_{ie}\frac{1}{\bar a_{le}}\Big)}_{\text{系数对 }x_{B_l}} x_{B_l} -\sum_{j\neq e}\underbrace{\Big(\bar a_{ij}-\bar a_{ie}\frac{\bar a_{lj}}{\bar a_{le}}\Big)}_{\bar a'_{ij}}x_j \end{aligned}
在新字典里,xBlx_{B_l} 已经变成非基变量(因为它离开了基),所以它会出现在右侧。这没问题:新非基集合是 N=(Ne)BlN'=(N\setminus{e})\cup{B_l}
因此更新公式:
  • RHS:  bˉi=bˉiaˉiebˉlaˉle (il)\boxed{\ \bar b'_i=\bar b_i-\bar a_{ie}\frac{\bar b_l}{\bar a_{le}}\ }\quad (i\neq l)
  • 非进基列 jej\neq e  aˉij=aˉijaˉieaˉljaˉle (il, je)\boxed{\ \bar a'_{ij}=\bar a_{ij}-\bar a_{ie}\frac{\bar a_{lj}}{\bar a_{le}}\ }\quad (i\neq l,\ j\neq e)
  • 对新加入的非基变量 xBlx_{B_l} 的系数(如果你显式保留这列):  aˉi,Bl=aˉie1aˉle (il)\boxed{\ \bar a'_{i,B_l}= -\bar a_{ie}\frac{1}{\bar a_{le}}\ }\quad (i\neq l)
3.2 更新 pivot 行(新的基变量是 xex_e
P0P0 直接得到新基行(把它写成“基变量 = 常数 − …”):
xe=bˉlaˉlebˉe1aˉlexBljeaˉljaˉlexj\boxed{ x_e=\underbrace{\frac{\bar b_l}{\bar a_{le}}}_{\bar b'_e} -\frac{1}{\bar a_{le}}x_{B_l} -\sum_{j\neq e}\frac{\bar a_{lj}}{\bar a_{le}}x_j }
即 pivot 行更新:
  • RHS:bˉe=bˉl/aˉle\bar b'_e=\bar b_l/\bar a_{le}
  • (je)(j\neq e)aˉej=aˉlj/aˉle\bar a'_{e j}= \bar a_{l j}/\bar a_{le}(注意在字典写法里右侧是 “(aˉejxj-\bar a'_{e j}x_j)”,所以很多实现里会存带符号的系数;你只要一致就行)。
  • 对离基变量 (Bl)(B_l):系数是 (1/aˉle)(1/\bar a_{le})(同样注意符号约定)。
3.3 更新目标行
原来目标:
z=z0+cˉexe+jecˉjxjz=z_0+\bar c_e x_e+\sum_{j\neq e}\bar c_j x_j
代入 P0P0
z=z0+cˉe(bˉlaˉle1aˉlexBljeaˉljaˉlexj)+jecˉjxj=(z0+cˉebˉlaˉle)z0+(cˉe1aˉle)对 xBl 的新检验数xBl+je(cˉjcˉeaˉljaˉle)cˉjxj\begin{aligned} z &=z_0+\bar c_e\Big(\frac{\bar b_l}{\bar a_{le}}-\frac{1}{\bar a_{le}}x_{B_l}-\sum_{j\neq e}\frac{\bar a_{lj}}{\bar a_{le}}x_j\Big)+\sum_{j\neq e}\bar c_j x_j\\ &=\underbrace{\Big(z_0+\bar c_e\frac{\bar b_l}{\bar a_{le}}\Big)}_{z_0'} +\underbrace{\Big(-\bar c_e\frac{1}{\bar a_{le}}\Big)}_{\text{对 }x_{B_l}\text{ 的新检验数}}x_{B_l} +\sum_{j\neq e}\underbrace{\Big(\bar c_j-\bar c_e\frac{\bar a_{lj}}{\bar a_{le}}\Big)}_{\bar c'_j}x_j \end{aligned}
所以:
  • 新目标常数项:  z0=z0+cˉebˉlaˉle \boxed{\ z_0' = z_0 + \bar c_e\frac{\bar b_l}{\bar a_{le}}\ }
  • 新检验数(对原非基 jej\neq e):  cˉj=cˉjcˉeaˉljaˉle (je)\boxed{\ \bar c'_j = \bar c_j-\bar c_e\frac{\bar a_{lj}}{\bar a_{le}}\ }\quad (j\neq e)
  • 对新非基变量 xBlx_{B_l} 的检验数:  cˉBl=cˉe1aˉle \boxed{\ \bar c'_{B_l} = -\bar c_e\frac{1}{\bar a_{le}}\ }

总结做法

单纯形表其实就是把字典的系数整理成一个表,并把“更新字典”实现成一次 pivot
  1. 选 pivot 元素:出基行 ll、进基列 ee,pivot 值 p=aˉlep=\bar a_{le}
  2. pivot 行更新:整行除以 pp,让 pivot 变成 1。
  3. 消元:对每一行 (rl)(r\neq l)(包括目标行),做 rowrrowr(rowr[e])rowl\text{row}_r \leftarrow \text{row}_r - (\text{row}_r[e])\cdot \text{row}_l

P13337【模板】线性规划

要输出方案数,直接将非基变量输出就行,问题在于不保证 bi0b_i \ge 0,所以需要两次单纯形,第一次单纯形求解一组可行解,第二次单纯形求解最大目标值,这里讲解第一次单纯形的方法。

1. 保证 bib_i 非负

如果 bi0b_i \le 0,就将整行乘以 1-1,使得 RHS 非负。

2. 引入松弛和剩余变量:

  1. \le:加松弛变量 si0s_i\ge 0
    aix+si=bia_i x + s_i = b_i
    这条约束通常可以用 sis_i 直接入基。
  2. \ge:减去剩余变量 si0s_i\ge 0
    aixsi=bia_i x - s_i = b_i
    这里的系数是 1-1不能直接用 sis_i 当基变量(基需要像单位列那样的 +1+1)。
  3. (=):不加松弛也不加剩余,直接
    aix=bia_i x = b_i
    也没有现成的“单位列”可入基。

3. 引入人工变量:

所以对 2、3 两类,要引入 人工变量 ai0a_i\ge 0
  • \geaixsi+ai=bia_i x - s_i + a_i = b_i
  • ==aix+ai=bia_i x + a_i = b_i

4. 构造辅助目标函数

不管你原来要 max 还是 min,它的目标是把所有人工变量都压到 0。 常见写法:
min w=ai\min\ w=\sum a_i
如果最优值 w>0w>0:说明无论怎么选 xx,都必须让至少一个人工变量 >0> 0 才能满足等式系统 ⇒ 原问题 不可行

5. 跑单纯形

初始基变量就是人工变量,初始 RHS 就是 bib_i

6. 进入第 2 次单纯形

  1. 把人工变量列删掉。
  2. 处理“人工变量仍在基里”的情况。 即便 w=0w=0,有时会出现某个人工变量仍是基变量,但它的值是 0。这时必须把它“换出基”,否则你删列会把基搞坏。
  3. 做法:
    • 在该行里找一个非人工变量列,且该列系数不为 0,把它 pivot 进来,把人工变量 pivot 出去。
    • 如果这一行里除人工变量外所有系数都为 0,而且 RHS 也为 0,说明这条约束线性相关,可以把这行删除。

P3980 志愿者招募

题意:
这个项目需要 nn 天才能完成,其中第 ii 天至少需要 aia_i 个人。布布通过了解得知,一共有 mm 类志愿者可以招募。其中第 ii 类可以从第 sis_i 天工作到第 tit_i 天,招募费用是每人 cic_i 元,求最小花费。
n1000,m10000n \le 1000,m\le 10000
题解:
xix_i 表示第 ii 个志愿者是否选择,bijb_{ij} 表示第 ii 个志愿者在第 jj 天是否工作,那么问题就是:
minimizei=1mcixi\begin{aligned} \text{minimize} \quad & \sum_{i=1}^m c_i x_i \\ \end{aligned} subject toi=1mbjixiaj(j=1,2,,n)xi0\begin{aligned}\text{subject to} \quad & \sum_{i=1}^m b_{ji} x_i \ge a_j \quad (j=1,2,\dots,n) \\ & x_i \ge 0 \end{aligned}
因为单纯形法是求解最大化目标的问题,给问题对偶一下:
maximizej=1najyj\begin{aligned} \text{maximize} \quad & \sum_{j=1}^n a_j y_j \\ \end{aligned} subject toi=1nbijyicj(j=1,2,,m)yi0\begin{aligned}\text{subject to} \quad & \sum_{i=1}^n b_{ij} y_i \le c_j \quad (j=1,2,\dots,m) \\ & y_i \ge 0 \end{aligned}
因为每个志愿者可以工作的区间是连续的,所以 b 每一行的 1 构成一个区间,转置一下满足引理的判定条件,所以 b 是全幺模矩阵,可以将问题转化为线性规划问题,直接用单纯形法求解即可。

P3337 防守战线

题意:
战线可以看作一个长度为 nn 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第 ii 号位置上建一座塔有 CiC_i 的花费,且一个位置可以建任意多的塔,费用累加计算。有 mm 个区间 [L1,R1],[L2,R2],,[Lm,Rm][L_1, R_1], [L_2, R_2], \cdots, [L_m, R_m],在第 ii 个区间的范围内要建至少 DiD_i 座塔。求最少花费。
n1000,m10000n \le 1000,m \le 10000
题解:
xix_i 表示序列第 ii 个位置选了几个塔,bijb_{ij} 表示对于第 ii 个区间第 jj 个位置是否在区间里面,那么问题就是:
minimizei=1ncixi\begin{aligned} \text{minimize} \quad & \sum_{i=1}^n c_i x_i \\ \end{aligned} subject toi=1nbjixidj(j=1,2,,m)xi0\begin{aligned}\text{subject to} \quad & \sum_{i=1}^n b_{ji} x_i \ge d_j \quad (j=1,2,\dots,m) \\ & x_i \ge 0 \end{aligned}
因为单纯形法是求解最大化目标的问题,给问题对偶一下:
maximizej=1mdjyj\begin{aligned} \text{maximize} \quad & \sum_{j=1}^m d_j y_j \\ \end{aligned} subject toi=1mbijyicj(j=1,2,,n)yi0\begin{aligned}\text{subject to} \quad & \sum_{i=1}^m b_{ij} y_i \le c_j \quad (j=1,2,\dots,n) \\ & y_i \ge 0 \end{aligned}
因为区间的位置是连续的,同上是全幺模矩阵,所以可以直接单纯形。

SGU 278 Fuel

题意:
一个燃料站有无限量的 NN 种燃料。每种燃料的密度为 aia_i ,成本为 bib_i ,强度为 cic_imm 公斤这种燃料的体积为 m×ai m \times a_i ,强度为 m×cim \times c_i ,成本为 m×bim \times b_i 美元。您的汽车可以储存各种燃料的混合物,但总容量不得超过 AA 。你有 BB 美元。你的任务是确定你能购买的最大燃料体积。请注意,你可以购买任何非负数的任何种类的燃料,而不一定是整数。(注意到这个体积计算公式不满足物理公式)
提示:这题考虑单老哥。
题解:
mim_i 表示燃料 i 购买的重量:
maxi=1Ncimi\max \sum_{i=1}^N c_i m_i s.t.aimiA,bimiB,mi0\text{s.t.}\quad \sum a_i m_i \le A,\quad \sum b_i m_i \le B,\quad m_i\ge 0
发现这个线性规划只有两个约束,因为最优解一定会落在顶点上,所以最优解最多用到两种燃料,但是不能直接枚举 O(n2)O(n^2) 会超时。
xi=cimi(第 i 种燃料贡献的强度)mi=xicix_i = c_i m_i \quad (\text{第 }i\text{ 种燃料贡献的强度}) \Rightarrow m_i = \frac{x_i}{c_i}
代回约束:
aicixiA,bicixiB,xi0\sum \frac{a_i}{c_i} x_i \le A,\qquad \sum \frac{b_i}{c_i} x_i \le B,\qquad x_i\ge 0
目标变成
maxxi\max \sum x_i
解释非常直观:
  • 想获得 1 单位强度,用燃料 ii 要消耗 pi=aici (体积/强度),qi=bici (金钱/强度)p_i=\frac{a_i}{c_i}\ (\text{体积/强度}),\quad q_i=\frac{b_i}{c_i}\ (\text{金钱/强度})
  • 所以每种燃料对应平面点 Pi=(pi,qi)P_i=(p_i,q_i)
如果总强度 S=xiS=\sum x_i,则总消耗为
(体积,金钱)=(pixi, qixi)=S(λipi, λiqi)(\text{体积},\text{金钱})= \left(\sum p_i x_i,\ \sum q_i x_i\right) = S\cdot \left(\sum \lambda_i p_i,\ \sum \lambda_i q_i\right)
其中 λi=xi/S\lambda_i=x_i/S,满足 λi0, λi=1\lambda_i\ge 0,\ \sum\lambda_i=1
也就是说,“单位强度的平均消耗点”
Pˉ=(pˉ,qˉ)=λiPi\bar P=(\bar p,\bar q)=\sum \lambda_i P_i
可以是 所有点 PiP_i 的凸包中的任意点
而可行性要求
SpˉA,SqˉBSmin(Apˉ,Bqˉ)S\bar p\le A,\quad S\bar q\le B \Rightarrow S\le \min\left(\frac{A}{\bar p},\frac{B}{\bar q}\right)
因此答案变为:
在凸包 conv(Pi)\text{conv}({P_i}) 上,最大化
F(p,q)=min(Ap,Bq)F(p,q)=\min\left(\frac{A}{p},\frac{B}{q}\right)
若存在 Pj=(pj,qj)P_j=(p_j,q_j) 满足
pjpi, qjqip_j\le p_i,\ q_j\le q_i
则燃料 ii 每 1 强度消耗不优于 jj,永远没必要用 ii
所以先按 pp 升序,保留 qq 严格下降的一条链即可。
k=BAk=\frac{B}{A}
对任意点 (p,q)(p,q)
  • qkpq\le kp,则 ApBq\frac{A}{p}\le \frac{B}{q},体积约束更紧,F(p,q)=ApF(p,q)=\frac{A}{p}
  • qkpq\ge kp,则钱更紧,F(p,q)=BqF(p,q)=\frac{B}{q}
因此最优点要么:
  1. 落在某个凸包顶点(只卡住一个约束时),
  2. 落在凸包边与直线 q=kpq=kp 的交点(两个约束同时卡住:Ap=Bq\frac{A}{p}=\frac{B}{q},此时一定最优)。
做法:
  • 先对所有凸包顶点算 FF 更新答案;
  • 再扫描每条边,判断端点 (f=qkp)(f=q-kp) 是否异号,若相交就线段-直线求交点并更新。
复杂度:O(NlogN)O(N\log N)

结语

比较遗憾的是写的东西在线性规划里面偏简单,并没有将线性规划和其他算法联系起来(比如网络流)等。
因时间关系,很多东西的证明被一笔带过或没有,在此将本文并未证明的东西列出来:
  1. 弱对偶定理和强对偶定理。
  2. 全幺模矩阵推出整数规划问题等价于线性规划问题,这个可以参见:https://www.luogu.com.cn/paste/xi6i8dkm。
  3. 如果矩阵的每一列的正负 1 形成一个区间那么就是全幺模。
  4. 单纯形的期望运行时间(参见平滑分析)。
  5. 二分图匹配和网络流的 LP 可行域是 IP。
  6. 原始-对偶方法里面问题 Q4 的可行性。
后续填坑。

评论

7 条评论,欢迎与作者交流。

正在加载评论...