- UID
- 1029342
- 性别
- 男
|
网络流的最经典应用就是最大流....给定一个图...给出每条边能流过的最大流量...求源点到汇点的最大流量....
求解网络流的基本思想就是每次寻找增广路(就是源点到汇点的一条可行路)..然后ans+=增广路能流过的流量..更新剩余网络..然后再做增广路...直到做不出增广路..关于网络流入门最难理解的地方就是剩余网络了....为什么在找到一条增广路后...不仅要将每条边的可行流量减去增广路能流过的流量...还要将每条边的反向弧加上增广路能流过的流量.?..原因是在做增广路时可能会阻塞后面的增广路...或者说做增广路本来是有个顺序才能找完最大流的.....但我们是任意找的...为了修正...就每次将流量加在了反向弧上...让后面的流能够进行自我调整...剩余网络的更新(就在原图上更新就可以了):
[url=][/url]
1 while (NowPoint!=1)
2 {
3 PrePoint=pre[NowPoint];
4 Network[PrePoint][NowPoint]-=MinFlow;
5 Network[NowPoint][PrePoint]+=MinFlow;
6 NowPoint=PrePoint;
[url=][/url]
7 }
最近又复习了下最大流问题,每次看这部分的内容都会有新的收获。可以说最大流问题的资料网上一搜一大把,根本没有必要自己写;但是大部分资料上的专业术语太多了,初学很难理解,至少我当年学这部分的时候前几次就没有看懂。所以我准备备份一点个人的理解。
图-1
如图-1所示,在这个运输网络中,源点S和汇点T分别是1,7,各边的容量为C(u,v)。图中红色虚线所示就是一个可行流。标准图示法如图-2所示:
其中p(u,v) / c(u,v)分别表示该边的实际流量与最大容量。
关于最大流 熟悉了什么是网络流,最大流也就很好理解了。就是对于任意的u∈V-{s},使得p(s,u)的和达到最大。上面的运输网络中,最大流如图-3所示:MaxFlow=p(1,2)+p(1,3)=2+1=3。
在介绍最大流问题之前,先介绍几个概念:残余网络,增广路径,反向弧,最大流定理以及求最大流的Ford-Fulkerson方法。
残余网络 增广路径 反向弧
观察下图-4,这种状态下它的残余网络如图-5所示:
也许现在你已经知道什么是残余网络了,对于已经找到一条从S 到T的路径的网络中,只要在这条路径上,把C(u,v)的值更新为C(u,v)-P(u,v),并且添加反向弧C(v,u)。对应的增广路径Path为残留网络上从S到T的一条简单路径。图-4中1,2,4,7就是一条增广路径,当然还有1,3,4,7。
此外在未做任何操作之前,原始的有向图也是一个残余网络,它仅仅是未做任何更新而已。
最大流定理
如果残留网络上找不到增广路径,则当前流为最大流;反之,如果当前流不为最大流,则一定有增广路径。
Ford-Fulkerson方法 介绍完上面的概念之后,便可以用Ford-Fulkerson方法求最大流了。为什么叫Ford-Fulkerson方法而不是算法,原因在于可以用多种方式实现这一方法,方式并不唯一。下面介绍一种基于广度优先搜索(BFS)来计算增广路径P的算法:Edmonds-Karp算法。
算法流程如下:
设队列Q:存储当前未访问的节点,队首节点出队后,成为已检查的标点;
Path数组:存储当前已访问过的节点的增广路径;
Flow数组:存储一次BFS遍历之后流的可改进量;
Repeat:
Path清空;
源点S进入Path和Q,Path[S]<-0,Flow[S]<-+∞;
While Q非空 and 汇点T未访问 do
Begin
队首顶点u出对;
For每一条从u出发的弧(u,v) do
If v未访问 and 弧(u,v) 的流量可改进;
Then Flow[v]<-min(Flow,c[v]) and v入队 and Path[v]<-u;
End while
If(汇点T已访问)
Then 从汇点T沿着Path构造残余网络;
Until 汇点T未被访问
求解最大流流最原始的算法是Ford_Fulkerson..也就是上面提到的每次找任意的找增广路...加上增广路流量再更新剩余网络...可以看出找最大流最耗时的地方就是寻找增广路..Edmonds_Karp是对Ford_Fulkerson的一个优化算法...Ford_Fulkerson是任意寻找增广路...而Edmonds_Karp是每次寻找从源点到汇点可行的最短的增广路...其优势是可以在前期就卡断很多不必要的寻找增广路而又到不了汇点的过程...其优化的方法也很简单..就是将Ford_Fulkerson找增广路的过程用BFS实现..
一个找最大流更好的优化则是Dinic..优化的地方也是找增广路的过程....Dinic做了一个预处理...将所有点按到源点的距离分层...然后在寻找增广路时..只有要拓展点与当前点的距离差为1时才拓展...其原理我还没弄明白..只知道算法的基本思路...
Dinic的过程是 :
1、BFS做出层次网络
2、DFS寻找增广路
CODE:
1 void Dinic()
[url=][/url]
2 {
3 while (BFS())
4 {
5 FindARoad=false;
6 DFS(1,1,oo);
7 }
8 }
部分转载自:http://blog.csdn.net/kk303/article/details/6707605 |
|