Netflow&Linear Programming 学习笔记
首先是Linear Programming(不按套路出牌啊喂)
解决$sum a_{i,j}x_j leq b_i, $ (x_i geq 0)
形式化的可以写成(Axleq b , x_igeq 0)
可以转换成松弛型,即添加未知量,使不等式变等式。
如果不符合小于号可以两边变号处理,这里系数无需保证正负。
解决线性规划即转成松弛型,做单纯形算法。
单纯形算法规则大概是寻找初始解,然后进行 转轴操作,具体看代码,很好记,背过就完了。
const double eps=1e-9,Inf=1e9;
const int N=1005;
int tp[N],id[N],n,m,ty;
double a[N][N];
void piovt(int r,int c){
double k=-a[r][c]; a[r][c]=-1;
swap(id[n+r],id[c]);
rep(i,0,n) a[r][i]/=k;
rep(i,0,m) if(a[i][c]&&r!=i){
k=a[i][c]; a[i][c]=0;
rep(j,0,n) a[i][j]+=k*a[r][j];
}
}
int solve(){
rep(i,1,n) id[i]=i;
while(1){
int i=0,j=0; double w=-eps;
rep(k,1,m) if(a[k][0]<w) w=a[i=k][0];
if(!i) break;
rep(k,1,n) if(a[i][k]>eps){ j=k; break; }
if(!j) return -1;
piovt(i,j);
}
while(1){
int i=0,j=0; double w=eps,t;
rep(k,1,n) if(a[0][k]>w) w=a[0][j=k];
if(!j) break; w=Inf;
rep(k,1,m) if(a[k][j]<-eps&&(t=-a[k][0]/a[k][j])<w) w=t,i=k;
if(!i) return 0;
piovt(i,j);
}
rep(i,n+1,n+m) tp[id[i]]=i-n;
return 1;
}
int main(){
scanf("%d%d%d",&n,&m,&ty);
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]=-a[i][j];
scanf("%lf",&a[i][0]);
}
int res=solve();
if(res==-1){
puts("Infeasible");
return 0;
}
if(!res){
puts("Unbounded");
return 0;
}
printf("%.9f
",a[0][0]);
if(ty) rep(i,1,n) printf("%.9f ",tp[i]?a[tp[i]][0]:0);
return 0;
}
全幺模最优解=整数解,可以优化
对偶:
最小化(sum_{j=1}^{n} c_jx_j),满足(sum_{j=1}^na_{i,j}x_j geq b_i)
最大化(sum_{i=1}^m b_iy_i),满足(sum_{i=1}^ma_{i,j}y_i leq c_i)
互为对偶。
最小化(c^Tx),满足(Axgeq b) 和最大化(b^Ty),满足(A^Tyleq c)
目标函数、约束 互换,结果大于/小于号取反。
二分图和网络流的那些结论可以用对偶来推。
线性规划转网络流
有道曰:“全幺模矩阵最优解为整数解”。
全幺模是什么,是erho的东西吗?
全幺模是指任何一个行数和列数相等的满秩子矩阵行列式值均为1或-1(自身不需要相等)
一个充分条件:
仅有0,1,-1,每列最多2个非零数。
行可被分为BC 2个集合,假如有一列包含了2个同号非零数那么它们所在的行被分在不同的集合,假如有一列包含了两个异号非零数那么他们所在的行被分在同一集合。
额,这判断怪难的,感觉真要到这一步还是打表猜猜看吧。
这种线性规划可以快速做
waiting for update
假如每列均为异号
这种可以转换成网络流,速度比单纯形快不少,因为其利用了这种矩阵的特殊性。
转换方法:
对于最小化(sum_{j=1}^{n} c_jx_j),满足(sum_{j=1}^ma_{i,j}x_j=b_i)
(A_x)中的正常数 c:连边(<S,x,c,0>)
(A_x)中的负常数 c:连边(<x,T,-c,0>)
(A_{x,v}=-1,A_{y,v}=1)范围([0,c]),(c_x=w) 连边(<x,y,c,w>)
(<u,v,流量,费用>)
跑最小费用最大流。
如果不好没有等式,先添加变量变成等式
考虑添加变量(z),其每个只出现一次且符号均为正负1
对于最小化(sum_{j=1}^{n} c_jx_j),满足(sum_{j=1}^ma_{i,j}x_j+z_i+b_i=0)
(A_{x,v}=-1,A_{y,v}=1)范围([0,c]),(c_x=w) 连边(<x,y,c,w>)
(A_x)中的正常数 c:连边(<S,x,c,0>) 钦定其流满
(A_x)中的负常数 c:连边(<x,T,-c,0>)同样也钦定流满
对于(z_i),建立(<i,T,infty,0>) 表示辅助量。
跑上下界最小费用最大流
如果是对偶问题输出方案,利用对偶问题答案建立差分约束模型跑最短路。原问题直接取流量。
Netflow
最大流=最小割
最小割模型:
区分集合ST,代价割边。
一道经典题:NOI2010海拔.
先建出最小割模型,十分经典+容易。
数据范围跑不过,发现是平面图,转平面图对偶。
平面图对偶:
性质:对偶图的最短路=原图最小割=原图最大流
转换方式:相邻的边的方向按照统一方式连成区域间的连边。
具体可以见狼抓兔子,还有此题。