费用流

费用流问题指的是在网络流边权新增“代价”这一属性后,在得到最大流量的前提下最小化代价之和的问题。

我们依然使用基于增广路的算法,只不过每次使用Bellman_Ford来寻找最短路。

如果要求代价最小可以在代价变为正时停止增广。

代码:

struct Edge{
 int u,v;LL cap,flow,cost;int next;
} E[maxn*2];

int n,m,x,y,S,T,Esize,pre[maxn],last[maxn];
LL val,c,d[maxn],a[maxn];

bool inq[maxn];

void addedge(int x,int y,LL v,LL c)
{
 E[++Esize]=(Edge){x,y,v,0,c,last[x]},last[x]=Esize;
 E[++Esize]=(Edge){y,x,0,0,-c,last[y]},last[y]=Esize;
}

bool Bellman_Ford(LL &flow,LL &cost)
{
 memset(inq,0,sizeof(inq)),inq[S]=1; //注意初始化细节
 rep(i,1,n) d[i]=INF;
 d[S]=0,a[S]=INF,pre[S]=0;
 
 queue<int> Q;Q.push(S);
 while (!Q.empty())
 {
  x=Q.front();Q.pop();

  for (int i=last[x];i;i=E[i].next)
   if ((E[i].cap>E[i].flow)&&(d[E[i].v]>(d[x]+E[i].cost)))
   {
    d[E[i].v]=d[x]+E[i].cost;
    pre[E[i].v]=i,a[E[i].v]=min(a[x],E[i].cap-E[i].cost);
    if (!inq[E[i].v]) Q.push(E[i].v),inq[E[i].v]=1;
   }
 }

 if (d[T]==INF) return false;

 flow+=a[T],cost+=a[T]*d[T],x=T; //代价为d[T],流量为a[T]
 while (x)
 {
  E[pre[x]].flow+=a[T],E[pre[x]^1].flow-=a[T];
  x=E[pre[x]].u;
 }
 return true;
}

LL MCMF()
{
 LL ans=0,flow=0;
 while (Bellman_Ford(flow,ans)); //存在增广路则一直增广
 return ans;
}
posted @ 2017-04-14 07:59  Krew  阅读(214)  评论(0)    收藏  举报