ZKW费用流的理解

ORZ ZKW费用流这样的神牛算法,也只有对最短路理解很深度人才能想得出来了吧

下面是我对这个算法的理解

ZKW算法主要分为AUG和Modlabel两个过程

其中Aug过程与普通的最大流DFS增广求法相似,但加入一个限制条件

满足等式Dist[U]=Dist[V]+edge.cost才允许增广

代码如下

int aug(int u,int flow)
  {   if (u==T) {ans+=flow*dis[S]; return flow;}
      vis[u]=1; int now=0;
      for (int i=base[u];i;i=v[i].next)
      { int x=v[i].x; 
        if (vis[x]||!v[i].f||dis[u]!=dis[x]+v[i].cost)
          continue;
       int tmp=aug(x,min(flow-now,v[i].f));
       if (tmp) v[i].f-=tmp; v[v[i].op].f+=tmp;
       now+=tmp;  if (now==flow) return flow; 
     } return now;
  }
Aug

你可能感到奇怪,这个过程并不会进行,应为一开始Dist应该都为0,所以还需要Modlabel来修改距离

int modlable()
  {  int del=inf;
     for (int i=S;i<=T;i++)
     if (vis[i]) 
     for (int j=base[i];j;j=v[j].next)
     if (v[j].f) {int x=v[j].x;  
      if (!vis[x]) del=min(del,dis[x]+v[j].cost-dis[i]);}
     if (del==inf) return 0;
     for (int i=S;i<=T;i++)
       if (vis[i]) vis[i]=0,dis[i]+=del,cur[i]=base[i]; return 1;
   }
Modlabel

当流网络不能再增广的时候,我们就修改距离,我们找出所有还有流量的边,并且边的起点被访问,但边终点未被访问

显然这些边都是因为不满足Dist[U]=Dist[V]+edge.cost才被阻断的,我们记录所有满足边下中Dist[V]+edge.cost-Dist[U]最小值

这样就能优先找出最短增广路,就能求出费用流了

最后将两个过程和在一起

int zkw()
  {  for (int i=S;i<=T;i++) cur[i]=base[i];
     do {while (aug(S,inf)) memset(vis,0,sizeof(vis));}
     while (modlable()); printf("%d\n",ans);
   }
ZKW

 

posted @ 2014-04-26 19:02  william's blog  阅读(1238)  评论(2编辑  收藏  举报

adopt your own virtual pet!