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; }
你可能感到奇怪,这个过程并不会进行,应为一开始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; }
当流网络不能再增广的时候,我们就修改距离,我们找出所有还有流量的边,并且边的起点被访问,但边终点未被访问
显然这些边都是因为不满足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); }