网络流总结

 

 

一.模板

 

1.最大流

EK算法:

 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 }
View Code

DINIC算法:

  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 }
View Code

sap领接矩阵:

 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 }
View Code

sap领接表:

 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 }
View Code

isap算法:

  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 }
View Code

 

2.最小割(没有源汇点):

 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 }
View Code

 

3.最小费用流:

 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 }
View Code

 

 

 

 

二.题目分类

 

 

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 

 

posted on 2017-12-31 14:27  h_z_cong  阅读(256)  评论(0编辑  收藏  举报

导航