首先来认识一下网络流中最大流的问题
给定一个有向图G=(V,E),把图中的边看做成管道,边权看做成每根管道能通过的最大流量(容量),给定源点s和汇点t,在源点有一个水源,在汇点有一个蓄水池,问s-t的最大水流量是多少
网络流图里,源点流出的量等于汇点流入的量,除源汇外的任何点,其流入量之和等于流出量之和 。
首先我们来看下面的图
s是源点,t是汇点
先这么想,先用dfs找出一条从s-t的路线,把他塞满,然后流量就是路径中容量最小的那条路的容量,然后把路径上的容量都剪去这个流量,再重新从s-t找可行路径,直到找不到为止
用这种思路看这个图
先走S-A-B-T,这样流量为100,并且没有可行路径了,即操作结束.
可是很明显,从S-A-T,S-B-T这两条路加起来的流量为200。所以这种思路是错的。
主要是过早的认为A-B的流量不为0
改进的思路:建立一个可以修改的网络,使得不合理的流可以被删掉
一种实现:对上次dfs时找到的流量路径上的边,添加一条“反向”边,反向边上的容量等于上次dfs时找到的该边上的流量,然后再利用“反向”的容量和其他边上剩余的容量寻找路径。
使用这种思路再求一次
第一次dfs后
第二次dfs(为了方便把容量为0的边删了)
这个时候已经没有可以走的边了,流量为200,dfs结束
为什么这种思路是正确的呢,网上有不少详细的证明。
Ford-Fulkerson算法
就是用这种思路做的
用dfs求增广路径,每次找到之后处理,直到找不到为止。
假设有n个定点,m条边,那么dfs的复杂度为n+m;
dfs运行c次
所以复杂度为c*(n+m);
但是dfs可能会运行很多次。
比如上面的图如果A-B中有条容量为1的边,那么运气不好的话,能执行200次dfs;
但实际上只要用2次就能找到
在每次增广的时候,选择从源到汇的具有最少边数的增广路径,即不是通过dfs寻找增广路径,而是通过bfs寻找增广路径。
这就是Edmonds-Karp 最短增广路算法
已经证明这种算法的复杂度上限为nm2 (n是点数, m是边数);
现在来说几道题目
1-〉POJ 1273
题意:网络流的裸题,1为源点,n为汇点,给定每条边的容量,求最大流,用EK算法
| 1273 | Accepted | 1052K | 0MS | G++ | 1430B |
1 #include <stdio.h> 2 #include <iostream> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 using namespace std; 9 #define N 300 10 #define INF 0x7fffffff 11 int Map[N][N]; 12 int path[N]; 13 //bool vis[N]; 14 int n,m; 15 bool bfs(int s,int t) 16 { 17 int p; 18 queue<int> q; 19 memset(path,-1,sizeof(path)); 20 //memset(vis,false,sizeof(vis)); 21 path[s]=s; 22 // vis[s]=true; 23 q.push(s); 24 while(!q.empty()) 25 { 26 p=q.front(); 27 q.pop(); 28 for(int i=1;i<=n;i++) 29 { 30 if(Map[p][i]>0&&path[i]==-1) 31 { 32 path[i]=p; 33 //vis[i]=true; 34 if(i==t) 35 return true; 36 q.push(i); 37 } 38 } 39 } 40 return false; 41 } 42 int EK(int s,int t) 43 { 44 int flow=0; 45 int d; 46 int i; 47 while(bfs(s,t)) 48 { 49 d=INF; 50 for(i=t;i!=s;i=path[i]) 51 { 52 d=min(d,Map[path[i]][i]); 53 } 54 for(i=t;i!=s;i=path[i]) 55 { 56 Map[path[i]][i]-=d; 57 Map[i][path[i]]+=d; 58 } 59 flow+=d; 60 } 61 return flow; 62 } 63 int main() 64 { 65 while(scanf("%d %d",&m,&n)!=EOF) 66 { 67 memset(Map,0,sizeof(Map)); 68 for(int i=1;i<=m;i++) 69 { 70 int from,to,flow; 71 scanf("%d %d %d",&from,&to,&flow); 72 Map[from][to]+=flow; 73 } 74 printf("%d\n",EK(1,n)); 75 } 76 77 return 0; 78 }