Note -「线性规划」学习笔记
\(\mathcal{Definition}\)
线性规划(Linear Programming, LP)形式上是对如下问题的描述:
\]
其中,\(\operatorname{maximize} z\) 即最大化 \(z\) 的值,亦可作 \(\operatorname{minimum} z\)(最小化),我们称其为目标函数。\(\operatorname{s.t.}\)(subject to,服从)称为约束条件。像这样的问题形式是线性规划的标准型。对于以下问题:
\]
则是所谓松弛型,因为我们可以通过引入松弛变量将标准型转化为松弛型:
\]
所以数学考试大方程题的第一问也是线性规划。此时,原有的变量 \(x_1,x_2,\cdots,x_n\) 称为非基变量,松弛用的变量 \(x_{n+1},x_{n+2},\cdots,x_{n+m}\)(\(m\) 为约束个数)称为基变量。更简便地,我们用矩阵来描述标准形式:
\]
其中,
\]
并称 \(\boldsymbol A\) 为约束矩阵,\(\boldsymbol b\) 为资源向量,\(\boldsymbol c\) 为价值向量,\(\boldsymbol x\) 为决策价值变量向量。
\(\mathcal{Algorithm}\)
说了那么多定义,接下来我们来设计一个算法求解线性规划问题。算法的基本思路为:
初始找出一个满足所有约束的初始解,通过这个解不断的更新,找到更优的解,直到找不到位置(类似爬山算法)。
可以发现这样一定能找到最优解,因为如果把求解的 \(X\) 当做 \(n\) 维空间的一个点,约束条件一定在 \(n\) 维空间中框出一个 \(n\) 维凸包,一 个解为凸包的一个顶点。凸面体从哪一个发现看都是单峰的,用爬山的算法是肯定能找到最优解的。
以
\operatorname{s.t.}\begin{cases}
x_4=30-(x_1+x_2+3x_3)\\
x_5=24-(2x_1+2x_2+5x_3)\\
x_6=36-(4x_1+x_2+2x_3)\\
x_1,x_2,\cdots,x_6\ge0
\end{cases}
\]
为例,不难看出初始解可为 \(\boldsymbol x=\begin{pmatrix}0,0,0,30,24,36\end{pmatrix}\)。接着变换第三个式子:
\Rightarrow x_1=9-\frac{1}4x_2-\frac{1}2x_3-\frac{1}4x_6
\]
代入 \(z\),得到:
\]
如此,交换 \(z\) 表达式中的一个非基变量和一个基变量的操作称为转轴(pivot)。形式地,设交换非基变量 \(x_u\) 与基变量 \(x_{v+n}\):
\]
上例中,转轴 \(x_1-x_6\),再将新的等式依次代入其他等式和目标函数,得到了 \(z=27+\frac{3}4x_2+\frac{3}2x_3-\frac{3}4x_6\)。如果我们通过若干次转轴使得 \(z\) 表达式中所有变量系数非正且 \(b_i\) 非负,就能得到此时的常数项为 \(z\) 的最值。总结一下,我们的算法分为两步:
- 找初始解。一种比较好写的随机算法:随机取 \(b_i<0\),再随机取 \(a_{ij}<0\),转轴 \(x_j-x_{i+n}\)。不存在 \(b_i\) 时结束。虽然这样仅保证 \(b_i\ge 0\)。更为精准的算法见学长的博客。
- 转轴使得 \(c_j\le0\)。取 \(j=\arg\max\{c_j|c_j>0\}\),找出 \(i=\arg\min\{\frac{b_i}{a_{ij}}|a_{ij}>0\}\),最后转轴 \(x_j-x_{i+n}\)。如此仍能保持 \(b_i\ge0\)。
无解当且仅当找不到初始解,这显而易见;无界当且仅当第二步找不到 \(i\),因为此时任意增大 \(c_j>0\) 的非基变量 \(x_j\),只会使 \(z\) 和 \(\boldsymbol b\) 中某些元素增大而不可能减少,一定能够保持合法性。
\(\mathcal{Example}\)
UOJ #179 \(97\) 分代码:
/* Clearink */
#include <ctime>
#include <cstdio>
#include <random>
#define rep( i, l, r ) for ( int i = l, rpbound##i = r; i <= rpbound##i; ++i )
#define per( i, r, l ) for ( int i = r, rpbound##i = l; i >= rpbound##i; --i )
const int MAXN = 50;
const double EPS = 1e-9;
int n, m, type, id[MAXN + 5], ref[MAXN + 5];
double a[MAXN + 5][MAXN + 5];
inline void iswp ( int& a, int& b ) { a ^= b ^= a ^= b; }
inline double dabs ( const double a ) { return a < 0 ? -a : a; }
inline int dcmp ( const double a, const double b ) {
return dabs ( a - b ) < EPS ? 0 : ( a < b ? -1 : 1 );
}
inline bool halfp () {
static std::mt19937 rnd ( time ( 0 ) ^ 20120712 );
return rnd () & 1;
}
inline void pivot ( const int r, const int c ) {
iswp ( id[r + n], id[c] );
double tmp = -a[r][c]; a[r][c] = -1;
rep ( i, 0, n ) a[r][i] /= tmp;
rep ( i, 0, m ) if ( i != r && dcmp ( a[i][c], 0 ) ) {
tmp = a[i][c], a[i][c] = 0;
rep ( j, 0, n ) a[i][j] += tmp * a[r][j];
}
}
inline int simplex () {
rep ( i, 1, n ) id[i] = i;
while ( true ) {
int i = 0, j = 0;
rep ( k, 1, m ) {
if ( !~dcmp ( a[k][0], 0 ) && ( !i || halfp () ) ) {
i = k;
}
}
if ( !i ) break;
rep ( k, 1, n ) {
if ( dcmp ( a[i][k], 0 ) == 1 && ( !j || halfp () ) ) {
j = k;
}
}
if ( !j ) return 2;
pivot ( i, j );
}
while ( true ) {
int i = 0, j = 0;
double mx = 0, mn = 1e9;
rep ( k, 1, n ) if ( dcmp ( a[0][k], mx ) == 1 ) mx = a[0][j = k];
if ( !j ) break;
rep ( k, 1, m ) {
if ( !~dcmp ( a[k][j], 0 ) && dcmp ( -a[k][0] / a[k][j], mn ) == -1 ) {
mn = -a[i = k][0] / a[k][j];
}
}
if ( !i ) return 1;
pivot ( i, j );
}
return 0;
}
int main () {
scanf ( "%d %d %d", &n, &m, &type );
rep ( i, 1, n ) scanf ( "%lf", &a[0][i] );
rep ( i, 1, m ) {
rep ( j, 1, n ) scanf ( "%lf", &a[i][j] ), a[i][j] *= -1;
scanf ( "%lf", &a[i][0] );
}
int res = simplex ();
if ( res == 2 ) puts ( "Infeasible" );
else if ( res ) puts ( "Unbounded" );
else {
printf ( "%.12f\n", a[0][0] );
if ( type ) {
rep ( i, 1, m ) ref[id[i + n]] = i;
rep ( i, 1, n ) {
printf ( "%.12f%c", ref[i] ? a[ref[i]][0] : 0, i ^ n ? ' ' : '\n' );
}
}
}
return 0;
}
Note -「线性规划」学习笔记的更多相关文章
- Note -「群论」学习笔记
目录 前置知识 群 置换 Burnside 引理与 Pólya 定理 概念引入 引例 轨道-稳定子(Orbit-Stabilizer)定理 证明 Burnside 引理 证明 Pólya 定理 证明 ...
- 「ExLucas」学习笔记
「ExLucas」学习笔记 前置芝士 中国剩余定理 \(CRT\) \(Lucas\) 定理 \(ExGCD\) 亿点点数学知识 给龙蝶打波广告 Lucas 定理 \(C^m_n = C^{m\% m ...
- 【Java】「深入理解Java虚拟机」学习笔记(1) - Java语言发展趋势
0.前言 从这篇随笔开始记录Java虚拟机的内容,以前只是对Java的应用,聚焦的是业务,了解的只是语言层面,现在想深入学习一下. 对JVM的学习肯定不是看一遍书就能掌握的,在今后的学习和实践中如果有 ...
- Pytorch线性规划模型 学习笔记(一)
Pytorch线性规划模型 学习笔记(一) Pytorch视频学习资料参考:<PyTorch深度学习实践>完结合集 Pytorch搭建神经网络的四大部分 1. 准备数据 Prepare d ...
- Note -「Lagrange 插值」学习笔记
目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...
- Note -「动态 DP」学习笔记
目录 「CF 750E」New Year and Old Subsequence 「洛谷 P4719」「模板」"动态 DP" & 动态树分治 「洛谷 P6021」洪水 「S ...
- Note -「圆方树」学习笔记
目录 圆方树的定义 圆方树的构造 实现 细节 圆方树的运用 「BZOJ 3331」压力 「洛谷 P4320」道路相遇 「APIO 2018」「洛谷 P4630」铁人两项 「CF 487E」Touris ...
- Note -「Dsu On Tree」学习笔记
前置芝士 树连剖分及其思想,以及优化时间复杂度的原理. 讲个笑话这个东西其实和 Dsu(并查集)没什么关系. 算法本身 Dsu On Tree,一下简称 DOT,常用于解决子树间的信息合并问题. 其实 ...
- Note -「多项式」基础模板(FFT/NTT/多模 NTT)光速入门
进阶篇戳这里. 目录 何为「多项式」 基本概念 系数表示法 & 点值表示法 傅里叶(Fourier)变换 概述 前置知识 - 复数 单位根 快速傅里叶正变换(FFT) 快速傅里叶逆变换(I ...
随机推荐
- 在CentOS 7.6 以 kubeadm 安装 Kubernetes 1.15 最佳实践
前言 Kubernetes作为容器编排工具,简化容器管理,提升工作效率而颇受青睐.很多新手部署Kubernetes由于"scientifically上网"问题举步维艰,本文以实战经 ...
- centos7 配置登录前和登录信息内容
登录之前提示信息: 登录之后提示信息: 上述中,只需修改对应的文件即可. 登录之前: vi /etc/issue 登录之后: vi /etc/motd 补充:将文件内容清空的方法,不是删除. 在前面文 ...
- 简单的树莓派4b装64位系统+docker和docker-compose
起因是这样的,我系统崩了 事先准备 wifi或网线 树莓派和电源 内存卡和读卡器 首先是装系统 去https://downloads.raspberrypi.org/raspios_arm64/ima ...
- 小程序canvas绘制纯色圆角区域 setdata数组某一项
小程序canvas绘制纯色圆角区域: //方法: roundRectPath:function(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x ...
- 360浏览器兼容模式下jsp页面访问不到js文件
360浏览器兼容模式下jsp页面访问不到js文件 查看自己js中的语法问题,不要用ES6的语法,编译不了故找不到js文件 const var of 码出高效 java 比较 所有整型包装类对象之间值的 ...
- FFT 傅里叶万岁
FFT --- Fast Foulier Transformation 以 $O(n \log n)$ 的速度计算 $\forall k=1,2,\dots,n, c[k]=\sum\limits_{ ...
- postman设置token等关联参数
登陆时登录成功后服务器会返回一个token,这个token作为第二步骤的入参:第二个步骤请求成功后服务器会返回一个新token,然后这个token作为第三步骤的入参!如此一来的话,要用postman做 ...
- Google Java 风格指南(Google Java Style Guide)
官方地址 google.github.io 本文档作为 Google 的 Java 编程语言源代码编码标准的完整定义.当且仅当它遵守此处的规则时,Java 源文件才被描述为 Google 风格. 前言 ...
- 【刷题-PAT】A1108 Finding Average (20 分)
1108 Finding Average (20 分) The basic task is simple: given N real numbers, you are supposed to calc ...
- Unable to open 'free_base.cpp': Unable to read file 'c:\Program Files\Microsoft VS Code\minkernel\crts\ucrt\src\appcrt\heap\free_base.cpp'
问题 vscode编写C++程序,使用microsoft C++ Unable to open 'cvt.cpp': Unable to read file 'c:\Program Files\Mic ...