这是须要证明的,预计证明也非常复杂。
(2)除此之外,每次DFS完后,会找到路径中容量最小的一条边。
在这条边之前的路径的容量是大于等于这条边的容量的。
那么从这条边之前的点。可能引发出别的增广路径。
比方说 S -> b -> c -> d -> T 是一条增广路径。容量最小的边是 b -> c。
可能存在一条 S -> b -> e -> f -> g -> T 这种增广路径。
这种话,在找到第一条增广路径后,仅仅须要回溯到 b 点,就能够继续找下去了。
这样做的优点是。避免了找到一条路径就从头開始寻找另外一条的开销。
也就是再次从 S 寻找到 b 的开销。
这个过程看似复杂。可是代码实现起来非常优雅,由于它的本质就是回溯!
(3)在同一次 DFS 中。假设从一个点引发不出不论什么的增广路径。就将这个点在层次图中抹去。
Description
Input
Output
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50
</pre><pre name="code" class="cpp">#include"stdio.h" #include"string.h" #define N 605 #define min(a,b) (a<b?a:b) const int inf=0x7fffffff; struct node { int u,v,w,next; }map[N*4]; int t,head[N],q[N],dis[N]; void add(int u,int v,int w) { map[t].u=u; map[t].v=v; map[t].w=w; map[t].next=head[u]; head[u]=t++; } int bfs(int s,int t) { int i,x,v,l,r; memset(dis,0,sizeof(dis)); //节点的高度标号 dis[s]=1; l=r=0; //队列两端 q[r++]=s; //模拟队列 while(l<r) { x=q[l++]; for(i=head[x];i!=-1;i=map[i].next) { v=map[i].v; if(map[i].w&&!dis[v]) { dis[v]=dis[x]+1; if(v==t) return 1; q[r++]=v; } } } return 0; } int dfs(int s,int t,int lim) { int i,v,tmp,cost=0; if(s==t) return lim; for(i=head[s];i!=-1;i=map[i].next) //枚举该点连通的全部边 { v=map[i].v; if(map[i].w&&dis[s]==dis[v]-1) { tmp=dfs(v,t,min(lim-cost,map[i].w)); if(tmp>0) { map[i].w-=tmp; //利用反向边的奇偶性。添加反向边的流量 map[i^1].w+=tmp; cost+=tmp; if(lim==cost) break; } else //在同一次 DFS 中。
假设从一个点引发不出不论什么的增广路径,就将这个点在层次图中抹去。 dis[v]=-1; } } return cost; } void dinic(int s,int t) { int ans=0; while(bfs(s,t)) ans+=dfs(s,t,inf); printf("%d\n",ans); } int main() { int u,v,w,n,m; while(~scanf("%d%d",&m,&n)) { t=0; memset(head,-1,sizeof(head)); while(m--) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,0); //建边,反向边流量为零 } dinic(1,n); } return 0; }
原文:http://www.cnblogs.com/gcczhongduan/p/5127955.html