引言: 在算法中一般存在最大-最小定理。
1 、最大匹配<==>最小覆盖
2、 最大流<==>最小割
最大流-最小割定理理解引自呆欧的形象表达:“多粗的管子,水就最多多大流量”,比如从自来水厂到用水大户工业小区A 能达到的水的最大流量是多大?考虑到可能从水厂到小区有不少到达的水管,那么最大的流量等于拆掉最少最细的水管后水厂不能给小区A 供水的那些水管流量的集合。当然这种说法并不不严谨,因为这里水管不是双向的,而在网络中谈论的信息流却可是是双向的。
其实最大流-最小割最难的地方在于构图了,还有必须掌握Dinic算法。
高效的求最大流算法——Dinci算法:
Dinci算法是基于“层次图”的时间效率优先的最大流算法。
层次:从源点走到终点的最短路长度。层次图:每次从源点到终点距离最短并且记录了多条增广路径(在找到最短路的过程记录了多条增广路径,因为找最短路径的过程中自然有分叉,有分叉那么增广路径条数不就变多了么)。在dfs遍历的时候必须按照层次走。
Dinic算法的思想是为了减少增广次数,建立一个辅助网络L,L与原网络G具有相同的节点数,但边上的容量有所不同,在L上进行增广,将增广后的流值回写到原网络上,再建立当前网络的辅助网络,如此反复,达到最大流
Dinic三步曲:
1、利用原网络构造层次图,顺便判断原网络还有无增广路。
2、利用构造的层次图求此次的最大流,若找不到增广路了则算法结束
3、更新原网络,即增广过程中遇见的边其正边以及逆边的的容量大小。
重复上述的三步。
模板:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 9 const int mn=222; 10 const int mm=10000; 11 const double oo=999999; 12 int node, st, sd, edge; 13 int reach[mm], next[mm]; 14 double flow[mm]; 15 int adj[mn], work[mn], dis[mn], que[mn]; 16 17 inline void init(int _node, int _st, int _sd) 18 { 19 node=_node, st=_st, sd=_sd; 20 for(int i=0; i<node; i++) 21 adj[i]=-1; 22 edge=0; 23 } 24 25 inline void addedge(int u, int v, double c1, double c2) 26 { 27 reach[edge]=v, flow[edge]=c1, next[edge]=adj[u],adj[u]=edge++; 28 reach[edge]=u, flow[edge]=c2, next[edge]=adj[v],adj[v]=edge++; 29 } 30 31 bool bfs() 32 { 33 int i,u,v,l,r=0; 34 for(i=0; i<node; ++i)dis[i]=-1; 35 dis[que[r++]=st]=0; 36 for(l=0; l<r; ++l) 37 for(i=adj[u=que[l]]; i>=0; i=next[i]) 38 if(flow[i]&&dis[v=reach[i]]<0) 39 { 40 dis[que[r++]=v]=dis[u]+1; 41 if(v==sd)return 1; 42 } 43 return 0; 44 } 45 46 double dfs(int u,double exp) 47 { 48 if(u==sd) return exp; 49 double tmp; 50 for(int &i=work[u],v; i>=0; i=next[i]) 51 if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=dfs(v,min(exp,flow[i])))>0) 52 { 53 flow[i]-=tmp; 54 flow[i^1]+=tmp; 55 return tmp; 56 } 57 return 0; 58 } 59 60 double Dinic() 61 { 62 double max_flow=0, flow; 63 while(bfs()) 64 { 65 for(int i=0; i<node; i++) work[i]=adj[i]; 66 while(flow=dfs(st,oo)) 67 max_flow+=flow; 68 } 69 return max_flow; 70 } 71 72 int main() 73 { 74 int n, m, k, T; 75 cin >> T; 76 while(T--) 77 { 78 scanf("%d%d%d",&n,&m,&k); 79 init(n+m+2,0,n+m+1); 80 double val; 81 for(int i=1; i<=n; i++) 82 { 83 scanf("%lf",&val); 84 addedge(st,i,log(val),0); 85 } 86 for(int i=1; i<=m; i++) 87 { 88 scanf("%lf",&val); 89 addedge(i+n,sd,log(val),0); 90 } 91 while(k--) 92 { 93 int u, v; 94 scanf("%d%d",&u,&v); 95 addedge(u,v+n,oo,0); 96 } 97 double ans=Dinic(); 98 printf("%.4lf\n",exp(ans)); 99 } 100 return 0; 101 }