最大流Edmonds-karp

  给出一个流网络G(V,E),入度为0是源点,出度为0是终点,网络中每条边有一个最大流量,要求算出能流入终点最大值,这就是网络流最大流的基本模型。流只是经过网络中的每个点,不会驻留,网络中的流总量是守恒的,例如基尔霍夫电流定律(流守恒的概念很重要)。流网络中还有正向边和反向边这两个概念,正向边即原有的边,反向边则是根据流守恒假想出来的与正向边相反的边。

  解决这一问题的Ford-Fulkerson method 基于三个重要思想:残留网络,增广路,割。下面对于这三个概念作一下简单介绍。

  残留网络:设网络中一个流f最大承载量为c(u,v),当前承载量为f(u,v),那么残留网络中对应f残留容量cf(u,v)=c(u,v)-f(u,v)。残留网络就是将原有的流网络中的每个流最大承载量换成残留容量,即Gf=(V,Ef),Ef={(u,v)属于G,cf(u,v)}。

  增广路:增广路p为在残留网络中一条从原点s流至终点t的一条简单路。该增广路的容量cf(u,v)=min{c(u,v),(u,v)在p上}。

  流网络的割:一个流网络的割(S,T)讲G分为不相交的两部分,其中源点s属于S,终点t属于T,割的净流被定义为将两部分相连所有边之和(包括反向边),记为f(S,T),而割的容量不包括反向边,记为c(S,T)。

      以上三个思想的给出解决了最大流最小割定理的证明(《算法导论》)。

  最大流最小割定理:对于G中任意一流f,下列条件等价:

  1)f是G的一个最大流。

  2)残留网络中不包含增广路。

  3)G中某个割(S,T),|f|=c(S,T)。

  由此得出了Ford-Fulkerson method 的做法,就是对于流网络G,初始化一个零流f,然后通过不断迭代找增广路,直至不存在增广路,此时f为最大流。而该方法关键在于如何找增广路,DFS显然不可行,基于BFS的算法叫做Edmonds-Karp算法。

  EK算法给出了一个时间复杂度为O(VE^2)的做法:

  EK(G , s ,t)

  1 for each edge(u,v)属于E[G]

  2   do f[u,v] = 0;

  3     f[v,u]=0;

  4 while BFS能找到一条最短增广路p

  5     do cf(p)=min{cf(u,v),(u,v)属于p}

  6    for each edge(u,v)属于p

  7          do f[u,v]=f[u,v]+cf(p)

  8         f[v,u]=-f[u,v];

      下面是POJ1273,注意输入的流可以叠加:

 1 #include<iostream>
2 #include<queue>
3 #include<cstring>
4 #define N 205
5 #define MAX 0xffffff
6 usingnamespace std;
7
8 int n,m,G[N][N],f[N][N],cf[N],pre[N];
9 queue <int> Q;
10
11 int BFS()
12 {
13 int u,v;
14 memset(pre,-1,sizeof(pre));
15 memset(cf,0,sizeof(cf));
16 cf[1]=MAX;
17 Q.push(1);
18 while(!Q.empty())
19 {
20 u=Q.front();
21 Q.pop();
22 for(v=2;v<=n;v++)
23 {
24 if(pre[v]==-1&&G[u][v]>f[u][v])
25 {
26 cf[v]=(cf[u]>(G[u][v]-f[u][v]))?(G[u][v]-f[u][v]):cf[u];
27 pre[v]=u;
28 Q.push(v);
29 }
30 }
31 }
32 return cf[n];
33 }
34
35 int edmonds_karp()
36 {
37 int v,ans=0;
38 memset(f,0,sizeof(f));
39 while(1)
40 {
41 int tmp;
42 tmp=BFS();
43 if(tmp==0) break;
44 ans+=tmp;
45 for(v=n;v!=1;v=pre[v])
46 {
47 f[pre[v]][v]+=tmp;
48 f[v][pre[v]]=-f[pre[v]][v];
49 }
50 }
51 return ans;
52 }
53
54 int main()
55 {
56 while(cin>>m>>n)
57 {
58 memset(G,0,sizeof(f));
59 int i,j,tmp;
60 while(m--)
61 {
62 cin>>i>>j>>tmp;
63 G[i][j]+=tmp;
64 }
65 cout<<edmonds_karp()<<endl;
66 }
67 }

     

posted @ 2011-07-22 19:55  acer01  阅读(490)  评论(0)    收藏  举报