网络流征程——Dinic再详解

来源:互联网 发布:mac能玩的手游 编辑:程序博客网 时间:2024/05/16 18:58

旧版链接



//感觉以前写的好敷衍

上次的文章绝大本分摘自别人的博客,这次我自己仔细的分析一下。

首先,简单的FolkFoukerson算法不断的增广时,可能走了太多的反向弧,即做了大量的无用功,所以我们规定了增广的一个条件——每次只增广最短的那条,那么可以保证这条增广路长度不下降,上限是O(n),如果我们简单用bfs进行增广,这就是著名的EmondKarp(EK)算法,那么整个算法的复杂度会达到(n*m^2),m可以达到n^2,即n^5,这显然很不理想。

我们再考虑一下EK算法,算法在不断BFS过程中,也重复走了太多同样的路,所以我们其实只需bfs一次,构造出一个单源最短路的层次图,那么我们接下来只需不断尝试当前层次图的最短路即可。这时由于最短路的唯一性,我们用dfs增广即可。

简单总结一下步骤:

1.BFS构造层次图,判断是否还有增广路。

2.DFS寻找增广路进行增广。

代码就不给注解了,旧版里就一个好——代码注释比较多(手动滑稽)


参考代码:

#include<cstdio>#include<algorithm>#include<queue>#include<cstring>using namespace std;const int M=210000;const int INF=0x3f3f3f3f;struct Edge{int to,cap,next;}e[M];int a[M],level[M];int ans=0;int n,m,S,T,EdgeCnt=0;queue<int> Q;void addedge(int u,int v,int f){int p=EdgeCnt;e[p].to=v;e[p].cap=f;e[p].next=a[u];a[u]=p;EdgeCnt++;}bool bfs(int S){memset(level,0xff,sizeof(level));level[S]=0;Q.push(S);while (!Q.empty()){int u=Q.front();Q.pop();int p=a[u];while (p!=-1){int v=e[p].to;if (e[p].cap>0 && level[v]==-1){level[v]=level[u]+1;Q.push(v);}p=e[p].next;}}return level[T]>-1;}int dfs(int u,int left){if (u==T || !Left)return left;int p=a[u],used=0;while (p!=-1){int v=e[p].to;if (e[p].cap>0 && level[v]==level[u]+1){int w=left-used;w=dfs(v,min(e[p].cap,w));used+=w;e[p].cap-=w;e[p^1].cap+=w;if (used==left)return left;}p=e[p].next;}return used;}int main(){scanf("%d%d%d%d",&n,&m,&S,&T);memset(a,0xff,sizeof(a));for (int i=1;i<=m;i++){int u,v,f;scanf("%d%d%d",&u,&v,&f);addedge(u,v,f);addedge(v,u,0);}while (bfs(S)){ans+=dfs(S,INF);}printf("%d\n",ans);return 0;}


原创粉丝点击