很早以前学过理论,3个月前又学了一遍写了一点笔记,现在觉得以(已)前(经)写(完)的(全)太(忘)丑(记)于是重写一遍
参考资料:
1.算法导论
2.2016国家集训队论文
$Maximize\quad \sum\limits_{j=1}^{n} c_jx_j$
$Satisfy\quad constraint:$
$\sum\limits_{j=1}^{n} a_{ij}x_j \le b_i,\ i=1,2,...,m$
$x_j \ge 0,\ j=1,2,...,n$
$n$个变量,$m+n$个约束
构造$m*n$的矩阵$A$,$m$维向量$b$,$n$维向量$c$
$Maximize\quad c^Tx$
$Satisfy\quad constraint:$
$Ax \le b$
$x \ge 0$
转化为标准型:
松弛型
松弛变量$x_{n+i}$
$ \sum\limits_{j=1}^{n} a_{ij}x_j \le b_i\ \rightarrow\ $$x_{n+i}=b_i - \sum\limits_{j=1}^{n} a_{ij}x_j,\ x_{n+i} \ge 0$
等式左侧为基本变量,右侧为非基本变量
单纯型算法
每个约束定义了$n$维空间中的一个半空间(超平面),交集形成的可行域是一个凸区域称为单纯型
目标函数是一个超平面,最优解在凸区域定点处取得
基本解:非基本变量值为$0$,基本变量为右侧的常数
基本可行解:所有$b_i \ge 0$
通过不断的转轴操作,在$n$维凸区域的顶点上不断移动(转轴),使得基本解的目标值不断变大,最终达到最优解
转轴:
选取一个非基本变量$x_e$为替入变量,基本变量$x_l$为替出变量,将其互换
为了防止循环,根据$Bland$规则,选择下标最小的变量
初始化:
算法导论上有一个辅助线性规划的做法
但我发现好多人都用了随机初始化的黑科技
在所有$b_i < 0$的约束中随机选一个作为$x_l$,再随机选一个$a_{le} < 0$的作为$x_e$,然后$Pivot(l,e)$后$b_i$就变正了...
代码实现:
直接用一个$a[][]$来保存目标函数和约束
$Pivot$里的各种操作推导一下很清楚,用了两个$trick$避免了一些判断
$id$用来保存基本变量和非基本变量集合
针对全幺模矩阵可以进行提取非零系数的优化
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int N=25; const double eps=1e-8,INF=1e15; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n,m,type; double a[N][N],ans[N]; int id[N<<1]; int q[N]; void Pivot(int l,int e){ swap(id[n+l],id[e]); double t=a[l][e]; a[l][e]=1; for(int j=0;j<=n;j++) a[l][j]/=t; for(int i=0;i<=m;i++) if(i!=l && abs(a[i][e])>eps){ t=a[i][e]; a[i][e]=0; for(int j=0;j<=n;j++) a[i][j]-=a[l][j]*t; } } bool init(){ while(true){ int e=0,l=0; for(int i=1;i<=m;i++) if(a[i][0]<-eps && (!l||(rand()&1))) l=i; if(!l) break; for(int j=1;j<=n;j++) if(a[l][j]<-eps && (!e||(rand()&1))) e=j; if(!e) {puts("Infeasible");return false;} Pivot(l,e); } return true; } bool simplex(){ while(true){ int l=0,e=0; double mn=INF; for(int j=1;j<=n;j++) if(a[0][j]>eps) {e=j;break;} if(!e) break; for(int i=1;i<=m;i++) if(a[i][e]>eps && a[i][0]/a[i][e]<mn) mn=a[i][0]/a[i][e],l=i; if(!l) {puts("Unbounded");return false;} Pivot(l,e); } return true; } int main(){ freopen("in","r",stdin); srand(317); n=read();m=read();type=read(); for(int i=1;i<=n;i++) a[0][i]=read(); for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++) a[i][j]=read(); a[i][0]=read(); } for(int i=1;i<=n;i++) id[i]=i; if(init() && simplex()){ printf("%.8lf\n",-a[0][0]); if(type){ for(int i=1;i<=m;i++) ans[id[n+i]]=a[i][0]; for(int i=1;i<=n;i++) printf("%.8lf ",ans[i]); } } }