学习笔记 --- 最小费用最大流
最小费用最大流,本人一只三种算法,MCMF、zkw(张昆玮)、Primal-Daul。然而基本没见人用过PD,多数都是MCMF和zkw。
对比起来,MCMF是基于spfa的一种算法,在稀疏图上十分高效;zkw算法是用spfa和KM重标号来进行计算的,在稠密图很高效,不过有一种图能够使zkw变慢:费用不小,容量不大,增广路比较长;
zkw最小费用最大流:
bool spfa()
{
memset(mark,0,sizeof(mark));
for (int i=S; i<=T; i++) dis[i]=-1;
h=0,t=1;
q[0]=T;mark[T]=1;dis[T]=0;
while (h<t)
{
int now=q[h];h++;mark[now]=0;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i^1].v && dis[now]+edge[i^1].c>dis[edge[i].to])
{
dis[edge[i].to]=dis[now]+edge[i^1].c;
if (!mark[edge[i].to])
{
mark[edge[i].to]=1;
q[t++]=edge[i].to;
}
}
}
return dis[S]!=-1;
}
int dfs(int loc,int low)
{
mark[loc]=1;
if (loc==T) return low;
int w,used=0;
for (int i=head[loc]; i; i=edge[i].next)
if (dis[edge[i].to]==dis[loc]-edge[i].c && edge[i].v && !mark[edge[i].to])
{
w=dfs(edge[i].to,min(low-used,edge[i].v));
ans+=w*edge[i].c;
edge[i].v-=w;edge[i^1].v+=w;
used+=w;if (used==low) return low;
}
return used;
}
void zkw()
{
int tmp=0;
while (spfa())
{
mark[T]=1;
while (mark[T])
{
memset(mark,0,sizeof(mark));
tmp+=dfs(S,inf);
}
}
}
---2016.03.16
浅谈线性规划类题目转费用流的建图方法:
首先添加松弛变量,将不等号都变为等号。分别用下一个式子减去上一个式子,如果每个变量只出现了两次且符号一正一负,那么可以转化为费用流。对于每个式子建立一个点,那么每个变量对应一条边,从一个点流出,向另一个点流入。这样,对于等式右边的常数 C,如果是正的,对应从源点向该点连一条流量 C,费用 0 的边;如果是负的对应从该点向汇点连一条流量 −C,费用 0 的边。对于每个变量,从它系数为正的式子向系数为负的式子连一条容量为inf,费用为它在目标函数里系数的边。这样网络流模型就构造完毕了。
详细例题可参考:http://blog.csdn.net/dad3zz/article/details/50815718
——It's a lonely path. Don't make it any lonelier than it has to be.