After a few days of learning and doing the problem, I use Rujia Book Network flow algorithm template to complete several network flow algorithms on the Hihocoder, Hihocoder may also continue to update the network flow algorithm, so I will go on to summarize.
This is mainly on the network flow algorithm modeling to do analysis and understanding, not specific analysis of network flow algorithm, network flow algorithm will be summarized separately.
Network Flow One · Ford-fulkerson algorithm
The problem is not modeled, is the standard network maximum flow solution, the graph after the completion of the direct application of the maximum flow algorithm can be solved. But here are a few things to keep in mind:
The so-called "residue Network" is to allow the program to traverse the reverse side of the record traffic that is added to the error. For example, the a-->b capacity of 10, the flow of 3, its meaning from A to B has gone 3 traffic, there are 7 traffic can go past, 3 traffic can be returned back.
Augmented path is to find the path from S to T can pass, so-called can pass is still there is not full stream edge can go some traffic. The idea of this kind of augmented path algorithm is to constantly find the "augmented path" on the "Residue Network", and then modify the traffic on the remaining network until it does not pass.
The code below is a template for the Rujia book "Getting Started with algorithmic competition":
const int MAXN = 505;const int INF = 0x7fffffff;struct Edge {int from, to, cap, flow; Edge (int u, int v, int c, int f): From (U), to (v), Cap (c), Flow (f) {}};struct Edmondskarp {int n, m; Vector<edge> edges; Vector<int> G[MAXN]; int A[MAXN]; int P[MAXN]; void init (int n) {for (int i = 0; i < n; ++i) g[i].clear (); Edges.clear (); } void Addedge (int from, int to, int caps) {Edges.push_back (Edge (from, to, Cap, 0)); Edges.push_back (Edge (to, from, 0, 0)); Reverse Edge M = edges.size (); G[from].push_back (m-2); G[to].push_back (m-1); } int Maxflow (int s, int t) {int flow = 0; for (;;) {memset (A, 0, sizeof (a)); Queue<int> Q; Q.push (s); A[s] = INF; while (! Q.empty ()) {int x = Q.front (); Q.pop (); for (int i = 0; i < g[x].size (); ++i) {Edge &e = Edges[g[x][i]]; if (!a[e.to] && e.cap > E.flow) {p[e.to] = G[x][i]; A[e.to] = min (a[x], e.cap-e.flow); Q.push (e.to); }} if (A[t]) break; } if (!a[t]) break; for (int u = t; u! = s; u = edges[p[u]].from) {Edges[p[u]].flow + = a[t]; Edges[p[u] ^ 1].flow-= a[t]; } flow + = A[t]; } return flow; }};int Main () {#ifdef LOCAL freopen ("Input.txt", "R", stdin); Freopen ("Sorted.txt", "w", stdout); #endif int N, M, u, V, c; CIN >> N >> M; Edmondskarp Ek; Construct the graph Ek.init (N); for (int i = 0; i < M; ++i) {cin >> u >> v >> c; Ek. Addedge (U, V, c); } cout << ek. Maxflow (1, N) << Endl; return 0;}
Network flow two • Maximum flow minimum cut theorem
This part is mainly to prove that the minimum cut equals the maximum flow, proving the detailed steps see above topic, here the main steps are recorded:
F (S, T) equals the stream coming out of s, equal to the current network traffic F. F (S, t) indicates the net flow of the cut (s, t).
For any one stream of the network, must be less than or equal to the capacity of any one cut (f (S, T) <= C (S, t)
For a network g= (V, E), the active point S meeting Point T, the following three are equivalent:
1, F is the maximum flow of Figure G
2, there is no augmented road residue network
3, for a cut of G (S, t), at this time F = C (S, t)
Prove:
1=>2: Suppose F is the maximum flow of Figure G, if the residual network exists augmented path p, the flow is FP, then there is flow f ' = f + fp > F, and F is the maximum flow contradiction.
2=>3: For any u S v T, there is f (u, v) = C (U, v), i.e. \[\sum f (U, v) =\sum C (U, v) = f (S, t) = C (S, t) = f\]
Thus, when the augmented path is not found, it must be the maximum flow, the maximum flow is equal to the minimum cut.
In addition, the problem requires the minimum cut set of S, in the cut (s, T), the calculated residual network from S to Traverse, the point that can be traversed is the s set, because the minimum cut is the maximum flow, the maximum flow in the residual network does not have an augmented path, that is, from S to T, so from S to start traversing, the point The set is S.
const int MAXN = 505;const int INF = 0x7fffffff;struct Edge {int from, to, cap, flow; Edge (int u, int v, int c, int f): From (U), to (v), Cap (c), Flow (f) {}};bool used[maxn];std::vector<int> rst;struct E dmondskarp {int n, m; Vector<edge> edges; Vector<int> G[MAXN]; int A[MAXN]; int P[MAXN]; void init (int n) {for (int i = 0; i < n; ++i) g[i].clear (); Edges.clear (); } void Addedge (int from, int to, int caps) {Edges.push_back (Edge (from, to, Cap, 0)); Edges.push_back (Edge (to, from, 0, 0)); Reverse Edge M = edges.size (); G[from].push_back (m-2); G[to].push_back (m-1); } int Maxflow (int s, int t) {int flow = 0; for (;;) {memset (A, 0, sizeof (a)); Queue<int> Q; Q.push (s); A[s] = INF; while (! Q.empty ()) {int x = Q.front (); Q.pop (); for (int i = 0; i < g[x].size (); ++i) { Edge &e = edges[g[x][i]]; if (!a[e.to] && e.cap > E.flow) {p[e.to] = G[x][i]; A[e.to] = min (a[x], e.cap-e.flow); Q.push (e.to); }} if (A[t]) break; } if (!a[t]) break; for (int u = t; u! = s; u = edges[p[u]].from) {Edges[p[u]].flow + = a[t]; Edges[p[u] ^ 1].flow-= a[t]; } flow + = A[t]; } return flow; } void Getmincutsets (int s) {rst.push_back (s); used[s] = true; for (int i = 0; i < g[s].size (); ++i) {Edge &e = edges[g[s][i]]; if (!used[e.to] && e.flow! = e.cap) {getmincutsets (e.to); }}}};int Main (int argc, char** argv) {#ifdef LOCAL freopen ("Input.txt", "R", stdin); Freopen ("Output.txt", "w", stdout); #endif///2 <= n <=, 1 <= m <= 20000 int N, M; CIN >> N >> M; Edmondskarp Ek; Ek.init (N); Construct the graph int u, V, c; for (int i = 0; i < M; ++i) {cin >> u >> v >> c; Ek. Addedge (U, V, c); } int flow = Ek. Maxflow (1, N); Ek. Getmincutsets (1); Std::cout << Flow << "<< rst.size () << Std::endl; for (int i = 0; i < rst.size ()-1; ++i) {cout << rst[i] << ""; } std::cout << Rst[rst.size ()-1] << Std::endl; return 0;}
Description: In the code GetMinCutSetS
is a DFS method, starting from a point to traverse to get the final S collection, nothing difficult. The results are stored in a vector.
Multi-matching of network flow San Shi graph
The multi-Match of the binary graph, the essence is to specify how many points in the X-set can be used, how many times the points in Y can be reused, if the traffic at a point in X is used, then this edge is full stream, then it cannot be reused. The capacity of the edge from the source point S to the X-set specifies how many times this point can be used! The capacity of the edges in the Y-set that point to the meeting point T is also the same meaning. Therefore, if the capacity in the Y-set is not exhausted, then the current flow (match) does not meet the desired requirements.
This question is used CheckMaxMatch
to determine if the edge of the sink point is full-flow.
const int MAXN = 1005;const int INF = 0x7fffffff;struct Edge {int from, to, cap, flow; Edge (int u, int v, int c, int f): From (U), to (v), Cap (c), Flow (f) {}};//for minimum cut two//minimum cut point the idea is to start DFS from S point on the residual network that originally asked for maximum flow, The points that can be traversed are those in the S collection, and/or the points that are not traversed are the points in the T collection. BOOL used[maxn];//std::vector<int> rst;struct edmondskarp {int n, m; Vector<edge> edges; Vector<int> G[MAXN]; int A[MAXN]; int P[MAXN]; void init (int n) {for (int i = 0; i < n; ++i) g[i].clear (); Edges.clear (); } void Addedge (int from, int to, int caps) {Edges.push_back (Edge (from, to, Cap, 0)); Edges.push_back (Edge (to, from, 0, 0)); Reverse Edge M = edges.size (); G[from].push_back (m-2); G[to].push_back (m-1); } int Maxflow (int s, int t) {int flow = 0; for (;;) {memset (A, 0, sizeof (a)); Queue<int> Q; Q.push (s); A[s] = INF; while (! Q.empty ()) { int x = Q.front (); Q.pop (); for (int i = 0; i < g[x].size (); ++i) {Edge &e = edges[g[x][i]]; if (!a[e.to] && e.cap > E.flow) {p[e.to] = G[x][i]; A[e.to] = min (a[x], e.cap-e.flow); Q.push (e.to); }} if (A[t]) break; } if (!a[t]) break; for (int u = t; u! = s; u = edges[p[u]].from) {Edges[p[u]].flow + = a[t]; Edges[p[u] ^ 1].flow-= a[t]; } flow + = A[t]; } return flow; } bool Checkmaxmatch (int N, int M) {for (int i = 1; I <= M; ++i) {for (int j = 0; J < G[n + I ].size (); ++J) {Edge &e = Edges[g[n + i][j]]; if (e.flow! = e.cap && e.flow > 0) {return false;} } } return true; }/*//traverse the minimum cut of the network to the S collection point, the result is stored in the above vector<int> rst; void getmincutsets (int s) {rst.push_back (s); Used[s] = true; for (int i = 0; i < g[s].size (); ++i) {Edge &e = edges[g[s][i]]; if (!used[e.to] && e.flow! = e.cap) {getmincutsets (e.to); }}} */};int main (int argc, char** argv) {#ifdef LOCAL freopen ("Input.txt", "R", stdin); Freopen ("Output.txt", "w", stdout); #endif int T; Cin >> T; while (t--) {int N, M; Cin >> N >> M; Edmondskarp Ek; Ek.init (N + M + 2); int M[MAXN + 5], A[MAXN + 5], B[MAXN + 5]; for (int i = 0; i < M; ++i) cin >> M[i]; for (int i = 0; i < N; ++i) {cin >> a[i] >> b[i]; int tmprecv; for (int j = 0; J < B[i]; ++j) {cin >> tmprecv; X-Y Ek. Addedge (i + 1), Tmprecv + N, 1); }} for (int i = 1; I <= N; ++i) {ek. Addedge (0, I, a[i-1]); } for (int i = 1; I <= M; ++i) {ek. Addedge (n + i, n + M + 1, m[i-1]); } ek. Maxflow (0, N + M + 1); cout << (EK. Checkmaxmatch (N, M)? "Yes": "No") << Endl; } return 0;}
Network Flow Four • Minimum path overlay
The method for building the map is:
1. Add source point S and meeting point T.
2, the demolition point, each point is split into two points, such as a split into A1, A2,b split into B1, B2.
3. Add a forward edge with a capacity of 1 from the source point to each point in the X collection.
4. Add a forward edge with a capacity of 1 from the Y collection to each point in the meeting point.
5, if a-B has a side, then from A1 to B2 add a capacity of 1 of the forward edge.
The minimum path overlay is the total number of points N-min cut. The proof was not written until I learned it.
Recommended to see the "Computer Algorithm design and analysis" in the network flow 24 problem of magic Ball, which is a very vague use of network flow of the minimum path coverage problem, very classic.
const int MAXN = 1005;const int INF = 0x7fffffff;struct Edge {int from, to, cap, flow; Edge (int u, int v, int c, int f): From (U), to (v), Cap (c), Flow (f) {}};//for minimum cut two//minimum cut point the idea is to start DFS from S point on the residual network that originally asked for maximum flow, The points that can be traversed are those in the S collection, and/or the points that are not traversed are the points in the T collection. BOOL used[maxn];//std::vector<int> rst;struct edmondskarp {int n, m; Vector<edge> edges; Vector<int> G[MAXN]; int A[MAXN]; int P[MAXN]; void init (int n) {for (int i = 0; i < n; ++i) g[i].clear (); Edges.clear (); } void Addedge (int from, int to, int caps) {Edges.push_back (Edge (from, to, Cap, 0)); Edges.push_back (Edge (to, from, 0, 0)); Reverse Edge M = edges.size (); G[from].push_back (m-2); G[to].push_back (m-1); } int Maxflow (int s, int t) {int flow = 0; for (;;) {memset (A, 0, sizeof (a)); Queue<int> Q; Q.push (s); A[s] = INF; while (! Q.empty ()) { int x = Q.front (); Q.pop (); for (int i = 0; i < g[x].size (); ++i) {Edge &e = edges[g[x][i]]; if (!a[e.to] && e.cap > E.flow) {p[e.to] = G[x][i]; A[e.to] = min (a[x], e.cap-e.flow); Q.push (e.to); }} if (A[t]) break; } if (!a[t]) break; for (int u = t; u! = s; u = edges[p[u]].from) {Edges[p[u]].flow + = a[t]; Edges[p[u] ^ 1].flow-= a[t]; } flow + = A[t]; } return flow; }};int Main (int argc, char** argv) {#ifdef LOCAL freopen ("Input.txt", "R", stdin); Freopen ("Output.txt", "w", stdout); #endif int N, M; CIN >> N >> M; Edmondskarp EDK; Edk.init (n + N); int u, v; for (int i = 1; I <= M; ++i) {cin >> u >> v; Edk. Addedge (U, v + N,1); } for (int i = 1; I <= N; ++i) {edk. Addedge (0, I, 1); Edk. Addedge (n + i, n + n + 1, 1); } cout << N-edk. Maxflow (0, n + N + 1) << Endl; return 0;}
Network flow five • Maximum weight closure sub-graph
Most powerful closed sub-graph: My understanding is that it is used to model and solve some of the problems of "income" and "expenditure" and seek the last largest income category. The modeling method is as follows:
1. Add source point S and meeting point T.
2, from the source point s to the X collection of each point a capacity for the point "revenue" of the forward edge.
3, from the Y set each point to the meeting point T even a capacity for the point "expenditure" of the forward edge.
4. If the points in the X and Y collections have dependencies, add an infinitely large, forward edge to each relationship from the X collection to the Y collection.
The final result is the sum of all incomes-the smallest cut.
const int MAXN = 1005;const int INF = 0x7fffffff;struct Edge {int from, to, cap, flow; Edge (int u, int v, int c, int f): From (U), to (v), Cap (c), Flow (f) {}};//for minimum cut two//minimum cut point the idea is to start DFS from S point on the residual network that originally asked for maximum flow, The points that can be traversed are those in the S collection, and/or the points that are not traversed are the points in the T collection. BOOL used[maxn];//std::vector<int> rst;struct edmondskarp {int n, m; Vector<edge> edges; Vector<int> G[MAXN]; int A[MAXN]; int P[MAXN]; void init (int n) {for (int i = 0; i < n; ++i) g[i].clear (); Edges.clear (); } void Addedge (int from, int to, int caps) {Edges.push_back (Edge (from, to, Cap, 0)); Edges.push_back (Edge (to, from, 0, 0)); Reverse Edge M = edges.size (); G[from].push_back (m-2); G[to].push_back (m-1); } int Maxflow (int s, int t) {int flow = 0; for (;;) {memset (A, 0, sizeof (a)); Queue<int> Q; Q.push (s); A[s] = INF; while (! Q.empty ()) { int x = Q.front (); Q.pop (); for (int i = 0; i < g[x].size (); ++i) {Edge &e = edges[g[x][i]]; if (!a[e.to] && e.cap > E.flow) {p[e.to] = G[x][i]; A[e.to] = min (a[x], e.cap-e.flow); Q.push (e.to); }} if (A[t]) break; } if (!a[t]) break; for (int u = t; u! = s; u = edges[p[u]].from) {Edges[p[u]].flow + = a[t]; Edges[p[u] ^ 1].flow-= a[t]; } flow + = A[t]; } return flow; } bool Checkmaxmatch (int N, int M) {for (int i = 1; I <= M; ++i) {for (int j = 0; J < G[n + I ].size (); ++J) {Edge &e = Edges[g[n + i][j]]; if (e.flow! = e.cap && e.flow > 0) {return false;} }} return true; }/*//traverse the minimum cut of the network to the S collection point, the result is stored in the above vector<int> rst; void getmincutsets (int s) {Rst.push_back (s ); Used[s] = true; for (int i = 0; i < g[s].size (); ++i) {Edge &e = edges[g[s][i]]; if (!used[e.to] && e.flow! = e.cap) {getmincutsets (e.to); }}} */};int main (int argc, char** argv) {#ifdef LOCAL freopen ("Input.txt", "R", stdin); Freopen ("Output.txt", "w", stdout); #endif int N, M; CIN >> N >> M; int B[MAXN], sum = 0; Edmondskarp Ek; Ek.init (N + M + 2); Number I indicates that the student with the invitation number I is required to spend an active value of b[i] for (int i = 1; I <= M; ++i) cin >> B[i]; for (int i = 1; I <= N; ++i) {int A, k, recvtmp; Cin >> a >> k; sum + = A; Ek. Addedge (0, I, a); for (int j = 1; j <= K; ++j) {cin >> recvtmp; Ek. Addedge (i, Recvtmp + N, INF); }} for (int i = 1; I <= M; ++i) {ek. AddeDge (i + N, n + M + 1, b[i]); } cout << Sum-ek. Maxflow (0, N + M + 1) << Endl; return 0;}
Hihocoder Network Flow Algorithm topic modeling Summary