起因是一道Timus的题目 , 长着一副经典的线性规划的模样:
单纯形法本身并不难理解 , 只是有很多名词可能让刚开始看的小伙伴有点为难。这里推荐一篇论文入门非常不错。 看到 Page12 就可以啦。然后让我们来看看一道很经典的网络流建图的难题:
BZOJ 1061 志愿者招募
这里设志愿者数量的向量为 X , 每天需要人数的向量为 Y , 目标最小值的系数向量为 C , 便可以得到一个最小化目标值的线性规划:
诶 , 当你正准备用单纯形法求这玩意的最大值的时候你会发现 , 这玩意好像我存不下。 因为当我添加了若干松弛变量之后 , 这玩意就是 108 级别的了。
当时这里我纠结了很久 , 但这就是一个很常见的针对稀疏矩阵的优化(弱省的学生学校里没有善良的学长啊)。
思路就是有的变量那一个列向量只有一个系数为1的值(其余都是0) , 所以我们不存这些东西 , 当我们 pivot 的时候我们 swap 一下两个变量的位置就好。
至此 ,此题就可以AC了。
这里贴一个会MLE但是思路清晰的代码 , 自己做的时候可以把 a , b 中的某个数组去掉即可
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1100;
const int maxm = 11000;
const double eps = 1e-7;
const double INF = 1e20;
int dcmp(double a) { return fabs(a)0:a<0?-1:1; }
int n , m;
double b[maxn][maxm] , a[maxm][maxn];
void dualize()
{
swap(++n, ++m);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j] = b[j][i];
}
void pivot(int l , int e)
{
for(int i=1;i<=n;i++) if(i!=l && dcmp(a[i][e]))
{
for(int j=1;j<=m;j++) if(j!=e) a[i][j] -= a[i][e]/a[l][e]*a[l][j];
a[i][e] /= -a[l][e];
}
for(int i=1;i<=m;i++) if(i!=e) a[l][i] /= a[l][e]; a[l][e] = 1/a[l][e];
}
double simplex()
{
double mn;
int e , l;
while(true)
{
for(e=1;eif(dcmp(a[n][e]) > 0) break;
if(e == m) return -a[n][m];
mn = INF;
for(int i=1;iif(dcmp(a[i][e]) > 0 && mn > a[i][m]/a[i][e]) mn = a[l=i][m]/a[i][e];
if(mn == INF) return INF;
pivot(l, e);
}
}
int main(int argc, char *argv[]) {
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%lf" , &b[i][m+1]);
for(int i=1,l,r,v;i<=m;i++)
{
scanf("%d%d%d" , &l,&r,&v);
for(int j=l;j<=r;j++) b[j][i] = 1;
b[n+1][i] = v;
}
dualize();
printf("%d" , (int)(simplex()+0.50));
return 0;
}
一些问题:
Q: 这玩意本来没次 pivot 的运算量就大 , 而且还是指数级别的算法, 为神马不超时呢?
A: 数据不好 , 好的话一样超时……
Q: 为什么你不记录此时的到底是哪些是松弛变量啊, 这样到最后不就不知道哪些变量的对应关系了么?
A: 是的 , 我确实应该记录这些变量的对应关系 , 但是此题不要求输出方案 , 这就免了(博主懒)
Q: 我看到网上的很多单纯形的代码很长的样子 , 你的代码这么短有没有暗伤啊?
A: 博主巨弱 , 表示目前没有发现
一个小小的总结:
我后来又尝试用单纯形法解决网络流的题目 , 正确性和通解的优势是明显的 , 因为通过代数建模比通过图论构造要灵活很多 , 就想用解析几何来做几何题一样。但是很多题目, 无论是时间还是空间都很紧迫 , 所以此方法在大多时候都不能上“正席” , 但是如果考试的时候一个网络流题目建模困难 , 而你会单纯形法 , 那么……(自由想象)