网络流总结
一.模板
1.最大流
EK算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> //EK算法 2 #include <queue> 3 #include<string.h> 4 using namespace std; 5 #define arraysize 201 6 int maxData = 0x7fffffff; 7 int capacity[arraysize][arraysize]; //记录残留网络的容量 8 int flow[arraysize]; //标记从源点到当前节点实际还剩多少流量可用 9 int pre[arraysize]; //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中 10 int n,m; 11 12 queue<int> myqueue; 13 int BFS(int src,int des) 14 { 15 int i,j; 16 while(!myqueue.empty()) //队列清空 17 myqueue.pop(); 18 for(i=1;i<m+1;++i) 19 { 20 pre[i]=-1; 21 } 22 pre[src]=0; 23 flow[src]= maxData; 24 myqueue.push(src); 25 while(!myqueue.empty()) 26 { 27 int index = myqueue.front(); 28 myqueue.pop(); 29 if(index == des) //找到了增广路径 30 break; 31 for(i=1;i<m+1;++i) 32 { 33 if(i!=src && capacity[index][i]>0 && pre[i]==-1) 34 { 35 pre[i] = index; //记录前驱 36 flow[i] = min(capacity[index][i],flow[index]); //关键:迭代的找到增量 37 myqueue.push(i); 38 } 39 } 40 } 41 if(pre[des]==-1) //残留图中不再存在增广路径 42 return -1; 43 else 44 return flow[des]; 45 } 46 47 int maxFlow(int src,int des) 48 { 49 int increasement= 0; 50 int sumflow = 0; 51 while((increasement=BFS(src,des))!=-1) 52 { 53 int k = des; //利用前驱寻找路径 54 while(k!=src) 55 { 56 int last = pre[k]; 57 capacity[last][k] -= increasement; //改变正向边的容量 58 capacity[k][last] += increasement; //改变反向边的容量 59 k = last; 60 } 61 sumflow += increasement; 62 } 63 return sumflow; 64 } 65 66 int main() 67 { 68 int i,j; 69 int start,end,ci; 70 while(cin>>n>>m) 71 { 72 memset(capacity,0,sizeof(capacity)); 73 memset(flow,0,sizeof(flow)); 74 for(i=0;i<n;++i) 75 { 76 cin>>start>>end>>ci; 77 if(start == end) //考虑起点终点相同的情况 78 continue; 79 capacity[start][end] +=ci; //此处注意可能出现多条同一起点终点的情况 80 } 81 cout<<maxFlow(1,m)<<endl; 82 } 83 return 0; 84 }
DINIC算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> ///dinic算法 2 #include <cstring> 3 #include <iostream> 4 #include <queue> 5 #include <vector> 6 7 using namespace std; 8 9 const int Maxn = 10000 + 10; 10 const int INF = 0x6fffffff >> 2; 11 12 struct edge 13 { 14 int from , to , cap , flow; 15 }; 16 17 struct Dinic{ 18 int n,m,s,t; 19 vector<edge> edges; 20 vector<int> f[Maxn]; 21 bool vis[Maxn]; 22 int d[Maxn]; 23 int cur[Maxn]; 24 25 void AddEdge(int from,int to,int cap) 26 { 27 edges.push_back((edge){from,to,cap,0}); 28 edges.push_back((edge){to,from,0,0}); 29 m = edges.size(); 30 f[from].push_back(m-2); 31 f[to].push_back(m-1); 32 } 33 34 bool BFS() 35 { 36 memset(vis,0,sizeof(vis)); 37 queue<int> q; 38 q.push(s); 39 d[s] = 0; 40 vis[s] = 1; 41 while(!q.empty()) 42 { 43 int x = q.front(); q.pop(); 44 for(int i=0;i<f[x].size();i++) 45 { 46 edge &e = edges[f[x][i]]; 47 if(!vis[e.to] && e.flow < e.cap) //只考虑残留网络中的弧 48 { 49 vis[e.to] = 1; 50 d[e.to] = d[x] + 1;//层次图 51 q.push(e.to); 52 } 53 } 54 } 55 return vis[t];//能否到汇点,不能就结束 56 } 57 int DFS(int x,int a)//x为当前节点,a为当前最小残量 58 { 59 if(x == t || a == 0) return a; 60 int flow = 0 , r; 61 62 for(int& i = cur[x];i < f[x].size();i++) 63 { 64 edge& e = edges[f[x][i]]; 65 if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 ) 66 { 67 e.flow += r; 68 edges[f[x][i] ^ 1].flow -= r; 69 flow += r;//累加流量 70 a -= r; 71 if(a == 0) break; 72 } 73 } 74 return flow; 75 } 76 int MaxFlow(int s,int t) 77 { 78 this->s = s; this->t = t; 79 int flow = 0; 80 while(BFS()) 81 { 82 83 memset(cur,0,sizeof(cur)); 84 flow += DFS(s,INF); 85 } 86 return flow; 87 } 88 }G; 89 90 int main() 91 { 92 int x,y,z; 93 int s,t; 94 scanf("%d",&G.n); 95 while(1) 96 { 97 scanf("%d%d%d",&x,&y,&z); 98 if(!(x|y|z)) break; 99 G.AddEdge(x,y,z); 100 } 101 scanf("%d%d",&s,&t); 102 printf("%d\n",G.MaxFlow(s,t)); 103 return 0; 104 }
sap领接矩阵:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int maze[MAXN][MAXN]; 2 int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; 3 int flow[MAXN][MAXN]; 4 5 int sap(int start, int end, int nodenum) 6 { 7 memset(cur, 0, sizeof(cur)); 8 memset(dis, 0, sizeof(dis)); 9 memset(gap, 0, sizeof(gap)); 10 memset(flow, 0, sizeof(flow)); 11 int u = pre[start] = start, maxflow = 0, aug = INF; 12 gap[0] = nodenum; 13 14 while(dis[start]<nodenum) 15 { 16 loop: 17 for(int v = cur[u]; v<nodenum; v++) 18 if(maze[u][v]-flow[u][v]>0 && dis[u] == dis[v]+1) 19 { 20 aug = min(aug, maze[u][v]-flow[u][v]); 21 pre[v] = u; 22 u = cur[u] = v; 23 if(v==end) 24 { 25 maxflow += aug; 26 for(u = pre[u]; v!=start; v = u, u = pre[u]) 27 { 28 flow[u][v] += aug; 29 flow[v][u] -= aug; 30 } 31 aug = INF; 32 } 33 goto loop; 34 } 35 36 int mindis = nodenum-1; 37 for(int v = 0; v<nodenum; v++) 38 if(maze[u][v]-flow[u][v]>0 && mindis>dis[v]) 39 { 40 cur[u] = v; 41 mindis = dis[v]; 42 } 43 if((--gap[dis[u]])==0) break; 44 gap[dis[u]=mindis+1]++; 45 u = pre[u]; 46 } 47 return maxflow; 48 }
sap领接表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct Edge 2 { 3 int to, next, cap, flow; 4 }edge[MAXN*MAXN]; 5 int tot, head[MAXN]; 6 7 int uN, vN, maze[MAXN][MAXN]; 8 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN]; 9 10 void add(int u, int v, int w) 11 { 12 edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0; 13 edge[tot].next = head[u]; head[u] = tot++; 14 edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0; 15 edge[tot].next = head[v]; head[v] = tot++; 16 } 17 18 int sap(int start, int end, int nodenum) 19 { 20 memset(dep, 0, sizeof(dep)); 21 memset(gap, 0, sizeof(gap)); 22 memcpy(cur, head, sizeof(head)); 23 int u = pre[start] = start, maxflow = 0,aug = INF; 24 gap[0] = nodenum; 25 while(dep[start]<nodenum) 26 { 27 loop: 28 for(int i = cur[u]; i!=-1; i = edge[i].next) 29 { 30 int v = edge[i].to; 31 if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1) 32 { 33 aug = min(aug, edge[i].cap-edge[i].flow); 34 pre[v] = u; 35 cur[u] = i; 36 u = v; 37 if(v==end) 38 { 39 maxflow += aug; 40 for(u = pre[u]; v!=start; v = u,u = pre[u]) 41 { 42 edge[cur[u]].flow += aug; 43 edge[cur[u]^1].flow -= aug; 44 } 45 aug = INF; 46 } 47 goto loop; 48 } 49 } 50 int mindis = nodenum - 1; 51 for(int i = head[u]; i!=-1; i = edge[i].next) 52 { 53 int v=edge[i].to; 54 if(edge[i].cap-edge[i].flow && mindis>dep[v]) 55 { 56 cur[u] = i; 57 mindis = dep[v]; 58 } 59 } 60 if((--gap[dep[u]])==0)break; 61 gap[dep[u]=mindis+1]++; 62 u = pre[u]; 63 } 64 return maxflow; 65 }
isap算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct Edge 2 { 3 int to, next, cap, flow; 4 }edge[MAXN<<2]; 5 int tot, head[MAXN]; 6 7 int gap[MAXN], dep[MAXN], cur[MAXN]; 8 9 void init() 10 { 11 tot = 0; 12 memset(head, -1, sizeof(head)); 13 } 14 15 void add(int u, int v, int w) 16 { 17 edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0; 18 edge[tot].next = head[u]; head[u] = tot++; 19 edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0; 20 edge[tot].next = head[v]; head[v] = tot++; 21 } 22 23 int Q[MAXN]; 24 void BFS(int start, int end) 25 { 26 memset(dep,-1,sizeof(dep)); 27 memset(gap,0,sizeof(gap)); 28 dep[end] = 0; 29 gap[0] = 1; 30 int front = 0, rear = 0; 31 Q[rear++] = end; 32 while(front!=rear) 33 { 34 int u = Q[front++]; 35 for(int i = head[u]; i!=-1; i=edge[i].next) 36 { 37 int v = edge[i].to; 38 if(dep[v]!=-1) continue; 39 Q[rear++] = v; 40 dep[v] = dep[u]+1; 41 gap[dep[v]]++; 42 } 43 } 44 } 45 46 int S[MAXN]; 47 int sap(int start, int end, int N) 48 { 49 BFS(start, end); 50 memcpy(cur,head,sizeof(head)); 51 int top = 0; 52 int u = start; 53 int ans = 0; 54 while(dep[start]<N) 55 { 56 if(u==end) 57 { 58 int Min = INF; 59 int inser; 60 for(int i = 0; i<top; i++) 61 if(Min>edge[S[i]].cap-edge[S[i]].flow) 62 { 63 Min = edge[S[i]].cap-edge[S[i]].flow; 64 inser = i; 65 } 66 for(int i = 0; i<top; i++) 67 { 68 edge[S[i]].flow += Min; 69 edge[S[i]^1].flow -= Min; 70 } 71 ans += Min; 72 top = inser; 73 u = edge[S[top]^1].to; 74 continue; 75 } 76 77 bool flag = false; 78 int v; 79 for(int i = cur[u]; i!=-1; i = edge[i].next) 80 { 81 v = edge[i].to; 82 if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u]) 83 { 84 flag = true; 85 cur[u] = i; 86 break; 87 } 88 } 89 90 if(flag) 91 { 92 S[top++] = cur[u]; 93 u = v; 94 continue; 95 } 96 97 int Min = N; 98 for(int i = head[u]; i!=-1; i = edge[i].next) 99 if(edge[i].cap-edge[i].flow && dep[edge[i].to]<Min) 100 { 101 Min = dep[edge[i].to]; 102 cur[u] = i; 103 } 104 if((--gap[dep[u]])==0) break; 105 gap[dep[u]=Min+1]++; 106 if(u!=start) u = edge[S[--top]^1].to; 107 } 108 return ans; 109 }
2.最小割(没有源汇点):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int mp[MAXN][MAXN]; 2 bool combine[MAXN]; 3 int n, m; 4 5 bool vis[MAXN]; 6 int w[MAXN]; 7 int prim(int times, int &s, int &t) //最大生成树? 8 { 9 memset(w,0,sizeof(w)); 10 memset(vis,0,sizeof(vis)); 11 for(int i = 1; i<=times; i++) //times为实际的顶点个数 12 { 13 int k, maxx = -INF; 14 for(int j = 0; j<n; j++) 15 if(!vis[j] && !combine[j] && w[j]>maxx) 16 maxx = w[k=j]; 17 18 vis[k] = 1; 19 s = t; t = k; 20 for(int j = 0; j<n; j++) 21 if(!vis[j] && !combine[j]) 22 w[j] += mp[k][j]; 23 } 24 return w[t]; 25 } 26 27 int mincut() 28 { 29 int ans = INF; 30 memset(combine,0,sizeof(combine)); 31 for(int i = n; i>=2; i--) //每一次循环,就减少一个点 32 { 33 int s, t; 34 int tmp = prim(i, s, t); 35 ans = min(ans, tmp); 36 combine[t] = 1; 37 for(int j = 0; j<n; j++) //把t点删掉,与t相连的边并入s 38 { 39 mp[s][j] += mp[t][j]; 40 mp[j][s] += mp[j][t]; 41 } 42 } 43 return ans; 44 }
3.最小费用流:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct Edge 2 { 3 int to, next, cap, flow, cost; 4 }edge[10010<<2]; 5 int tot, head[MAXN]; 6 int pre[MAXN], dis[MAXN]; 7 bool vis[MAXN]; 8 int N; 9 10 void init(int n) 11 { 12 N = n; 13 tot = 0; 14 memset(head, -1, sizeof(head)); 15 } 16 17 void add(int u, int v, int cap, int cost) 18 { 19 edge[tot].to = v; edge[tot].cap = cap; edge[tot].cost = cost; 20 edge[tot].flow = 0; edge[tot].next = head[u]; head[u] = tot++; 21 edge[tot].to = u; edge[tot].cap = 0; edge[tot].cost = -cost; 22 edge[tot].flow = 0; edge[tot].next = head[v]; head[v] = tot++; 23 } 24 25 bool spfa(int s, int t) 26 { 27 queue<int>q; 28 for(int i = 0; i<=N; i++) 29 { 30 dis[i] = INF; 31 vis[i] = false; 32 pre[i] = -1; 33 } 34 35 dis[s] = 0; 36 vis[s] = true; 37 q.push(s); 38 while(!q.empty()) 39 { 40 int u = q.front(); 41 q.pop(); 42 vis[u] = false; 43 for(int i = head[u]; i!=-1; i = edge[i].next) 44 { 45 int v = edge[i].to; 46 if(edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost) 47 { 48 dis[v] = dis[u]+edge[i].cost; 49 pre[v] = i; 50 if(!vis[v]) 51 { 52 vis[v] = true; 53 q.push(v); 54 } 55 } 56 } 57 } 58 if(pre[t]==-1) return false; 59 return true; 60 } 61 62 int minCostMaxFlow(int s, int t, int &cost) 63 { 64 int flow = 0; 65 cost = 0; 66 while(spfa(s,t)) 67 { 68 int Min = INF; 69 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 70 { 71 if(Min>edge[i].cap-edge[i].flow) 72 Min = edge[i].cap-edge[i].flow; 73 } 74 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 75 { 76 edge[i].flow += Min; 77 edge[i^1].flow -= Min; 78 cost += edge[i].cost*Min; 79 } 80 flow += Min; 81 } 82 return flow; 83 }
二.题目分类
1.最大流
1) 一般形式:
HDU1532 Drainage Ditches
HDU4280 Island Transport
HDU3416 Marriage Match IV
2)多源多汇问题(建立超级源、汇点):
POJ2289 Jamie's Contact Groups
POJ2112 Optimal Milking
POJ3189 Steady Cow Assignment
POJ3281 Dining
POJ3436 ACM Computer Factory
POJ1087 A Plug for UNIX
POJ2516 Minimum Cost
POJ1459 Power Network
HDU4292 Food
HDU2732 Leapin' Lizards
HDU3081 Marriage Match II
3)结点容量(拆点或直接连向源、汇点):
POJ3281 Dining
POJ3436 ACM Computer Factory
POJ1087 A Plug for UNIX
POJ1459 Power Network
HDU4292 Food
UVA10480 Sabotage
HDU2732 Leapin' Lizards
HDU3081 Marriage Match II
HDU3338 Kakuro Extension
4)有容量上下界问题:
5)二分图(点)带权最大独立集:
HDU1569 方格取数(2)
6)公平分配问题:
POJ2289 Jamie's Contact Groups
POJ2112 Optimal Milking
POJ3189 Steady Cow Assignment
2.最小割
1)求最小割:
POJ2914 Minimum Cut(无源汇)
UVA10480 Sabotage(有源汇)
HDU1569 方格取数(2)
2)求最小割集:
UVA10480 Sabotage
3.最小费用流
1) 一般形式:
POJ2135 Farm Tour
POJ2195 Going Home
POJ2516 Minimum Cost
2)费用与流量平方成正比:
HDU3667 Transportation
3)流量不固定的最小费用流(费用有正有负):
UVA11613 Acme Corporation
4)区间k覆盖问题:
POJ3680 Intervals