线性规划(单纯形法)知识整理
Posted joker-yza
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性规划(单纯形法)知识整理相关的知识,希望对你有一定的参考价值。
内容有点多,自己写是不可能的,下面挂两篇博客,复习的时候可以看看
该算法的时间复杂度很迷,精度也很奇怪,$uoj$的题用$eps=1e-13$就炸了,用$1e-11$较好
这里挂两个模板,对应不同的标准型,需要的时候可以选一个用,有时可以避免求基本解
但注意若$b_i < 0$,无论哪个板都要先初始化求基本解
模板:
$Case 1$: 最大化 $sum_{j=1}^nc_jx_j$
满足$m$条约束 $sum_{j=1}^na_{ij}x_j leqslant b_i$
同时$n$个变量需要满足 $x_j geqslant 0$
代码:(uoj179)
#include<bits/stdc++.h> using namespace std; const int maxn = 50; const double eps = 1e-11; int n, m, typ, id[maxn], b[maxn]; double a[maxn][maxn]; void pivot(int x, int y) { swap(id[x+n], id[y]); double t = -a[x][y]; a[x][y] = -1; for(int i = 0; i <= n; ++i) a[x][i] /= t; for(int i = 0; i <= m; ++i) if(a[i][y] && x != i) { t = a[i][y]; a[i][y] = 0; for(int j = 0; j <= n; ++j) a[i][j] += a[x][j] * t; } } void init() { for(int i = 1; i <= n; ++i) id[i] = i; int p, q; double t, w; while(1) { p = q = 0; w = - eps; for(int i = 1; i <= m; ++i) if(a[i][0] < w) { w = a[i][0]; p = i; } if(!p) return; for(int i = 1; i <= n; ++i) if(a[p][i] > eps) { q = i; break; } if(!q) { printf("Infeasible"); exit(0); } pivot(p, q); } } void simplex() { int p, q; double w; while(1) { p = q = 0; w = eps; for(int i = 1; i <= n; ++i) if(a[0][i] > w) { p = i; w = a[0][i]; } if(!p) return; w = 1e20; for(int i = 1; i <= m; ++i) if(a[i][p] < - eps && - a[i][0] / a[i][p] < w) { w = - a[i][0] / a[i][p]; q = i; } if(!q) { printf("Unbounded"); exit(0); } pivot(q, p); } } int main() { scanf("%d%d%d", &n, &m, &typ); for(int i = 1; i <= n; ++i) scanf("%lf", &a[0][i]); for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { scanf("%lf", &a[i][j]); a[i][j] *= -1; } scanf("%lf", &a[i][0]); } init(); simplex(); printf("%.10f ", a[0][0]); if(!typ) return 0; for(int i = n + 1; i <= n + m; ++i) b[id[i]] = i - n; for(int i = 1; i <= n; ++i) printf("%.10f ", b[i]? a[b[i]][0]: 0); return 0; }
PS:只有97分
$Case 2$: 最小化 $sum_{j=1}^nc_jx_j$
满足$m$条约束 $sum_{j=1}^na_{ij}x_j geqslant b_i$
同时$n$个变量需要满足 $x_j geqslant 0$
代码:(bzoj3265志愿者招募加强版)
#include<bits/stdc++.h> using namespace std; const int maxm = 10005, maxn = 1005; const double eps = 1e-11; int n, m, id[maxm]; double a[maxm][maxn]; void pivot(int x, int y) { double w = -a[x][y]; a[x][y] = -1; for(int i = 0; i <= n; ++i) a[x][i] /= w; for(int i = 0; i <= m; ++i) if(a[i][y] && x != i) { w = a[i][y]; a[i][y] = 0; for(int j = 0; j <= n; ++j) a[i][j] += w * a[x][j]; } } void simplex() { int p, q; double w; while(1) { p = q = 0; w = eps; for(int i = 1; i <= n; ++i) if(a[0][i] > w) { w = a[0][i]; p = i; break; } if(!p) return ; w = 1e18; for(int i = 1; i <= m; ++i) if(a[i][p] < -eps && - a[i][0] / a[i][p] < w) { w = - a[i][0] / a[i][p]; q = i; } pivot(q, p); } } int main() { scanf("%d%d", &n, &m); int l, r, num; for(int i = 1; i <= n; ++i) scanf("%lf", &a[0][i]); for(int i = 1; i <= m; ++i) { scanf("%d", &num); for(int j = 1; j <= num; ++j) { scanf("%d%d", &l, &r); for(int k = l; k <= r; ++k) a[i][k] = -1; } scanf("%lf", &a[i][0]); } simplex(); printf("%.0f", a[0][0]); return 0; }
PS:这道题一开始写的$Case 1$,当然需要先求基本解,于是就T飞了
以上是关于线性规划(单纯形法)知识整理的主要内容,如果未能解决你的问题,请参考以下文章
线性规划中的单纯形法与内点法(原理步骤以及matlab实现)
线性规划中的单纯形法与内点法(原理步骤以及matlab实现)