题目
http://www.lydsy.com/JudgeOnline/problem.php?id=1061
题解
终于搞完了单纯形,还真不是个简单的东西,但是理解之后,算法挺简单的,证明只有自动略过了qwq。
学习单纯形推荐算导29章,严密又不失详细。
标准的线性规划式子是,
A=(aij),b=(bi),c=(ci),x=(xi)
大小的话A为m* n,b为m* 1,c为1* n,a为1 *n.c右上角的T表示转置。
会出现一些问题使得它不是个标准型。有以下几种
1.MAX函数是MIN,对目标函数f取负改成MAX即可
2.变量
xi
没有非负约束,那么拆成两个变量
xi=x′i−x′′i
,并且有
x′i>=0
和
x′′i>=0
带回原式即可。
3.是等式约束,不是不等式约束(不等式约束不能是严格不等),如果有
X=b
拆为
X<=b
并且
X>=b
即可。
4.是>=而不是<=两边同时乘一个符号即可。
化成这样之后化成松弛型线性规划式子。(N是非基变量集合,即化成松弛型之后在右边的变量)
弄好了之后,为了方便解,一般要变成一种松弛型的等式形式。即对于第i个约束
变成
即可,后续还会对这个式子进行变形,一个定义,等号左边的变量叫做基本变量,右边的叫非基变量,然后把原函数值用z代替,用N表示非基变量集合,B表示基本变量集合。
好像这里需要初始化一下以保证初始基本解可行,因为本题特殊,只需要对偶一下就可以,对偶的具体操作以及后续计算可以看这里–传送
然后反复使用单纯形法,感觉就是不断增加z的表达式中的v,不断拿一个基变量出来和非基变量进行替换(即pivot操作),直到 ci 全部为负数,返回答案。
后续初始化还要学学.学的还很多
以及这道题很神的费用流做法,以及啥是zkw费用流,提及zkw的话还有,zkw线段树qwq。
代码
相当于自己的一个板子啦qwq。
//QWsin
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-7;
const int maxm=10000+10;
const int maxn=1000+10;
const double INF=(1ull<<63);
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;
double c[maxn],b[maxm],cof[maxm][maxn];
//who in ,who out , the ans
inline void Pivot(int in,int out,double &z)
{
b[out]/=cof[out][in];
cof[out][in]=1/cof[out][in];
for(int i=1;i<=n;++i) if(i!=in) cof[out][i]*=cof[out][in];
for(int i=1;i<=m;++i) if(i!=out && fabs(cof[i][in]) > eps )//fabs(cof[out][in]) > eps 你这样写是会把剪枝去掉然后T到飞起的
{
b[i]-=b[out]*cof[i][in];
for(int j=1;j<=n;++j) if(j!=in) cof[i][j]-=cof[out][j]*cof[i][in];
cof[i][in]=-cof[i][in]*cof[out][in];
}
z+=c[in]*b[out];//v增加的量
for(int i=1;i<=n;++i) if(i!=in) c[i]-=c[in]*cof[out][i];
c[in]=-c[in]*cof[out][in];
}
inline double Simplex()
{
double z=0;
while(1)
{
int in,out;
for(in=1;in<=n;++in) if(c[in]>eps) break;
if(in==n+1) break;//not found
double jin=INF;//find the YveShu that is the most Jin
for(int i=1;i<=m;++i) if(cof[i][in] > eps && b[i]/cof[i][in]<jin)
jin=b[i]/cof[i][in],out=i;
if(jin==INF) return INF;
Pivot(in,out,z);
}
return z;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i) c[i]=read();
for(int i=1,s,t;i<=m;++i)
{
s=read();t=read();
for(int j=s;j<=t;++j) cof[i][j]=1;
b[i]=read();
}
printf("%lld\n",(long long)(Simplex()+0.5));
return 0;
}