Learning Summary - Network Flow

(Square) understanding network flow

1. What is the network

Definition 1.1 Network

Network is a directed graph. Vertices called nodes , called edges arc figure each side has a capacity , which flows through the edges of the flow rate must not exceed the edge of capacity . FIG there are two special nodes specified, source \ (S \) and sink \ (T \) . Traffic from \ (S \) flows \ (T \) ( \ (S \) out without, \ (T \) not only into).

Network can be used to simulate a road traffic system, in the liquid pipe, anything current in the circuit or something similar at the network node in a swimming.

1.2 Properties of the network

1.2.1 flow balance

The introduction of several concepts:

  • Feasible flow : generally speaking, does not exceed the capacity of stream
  • The maximum flow : the flow maximum feasible flow

In addition to source and sink for any node are: to flow into the node traffic flowing out of the node's traffic equal.

1.2.2 antisymmetry

The introduction of several concepts:

  • Residual network : an original network after subtracting a feasible flow of FIG.
  • Zo Canton Road : from \ (S \) to \ (T \) of a road, and the capacity of each edge is greater than 0

Set flow rate for the \ (F. \) , \ (F. (X, Y) = K \) represents from node \ (X \) to node \ (Y \) traffic to \ (K \) , then:
\ [ F (u, v) = -F
(v, u) \] Accordingly, we introduce the reverse side.

If the edge \ ((u, v) \ ) have \ (F \) flow, the edge \ ((v, u) \ ) have \ (F \) capacity

(B) the maximum flow

1 solving the maximum flow

1.1 The maximum flow properties

The nature of the network can be obtained:

If the residual network can not be found on the enlargement of Canton Road , then the current flow is the maximum flow

If the residual network is present on the enlargement of a wide road , then the current flow is definitely not the maximum flow (flow rate must be greater than zo wide passage 0)

1.2 \ (Edmonds-Karp \) augmenting path algorithm

1.2.1 algorithm flow

The algorithm is based on the maximum flow required properties.

  1. Used on the network \ (bfs \) to find augmenting path
  2. The way to broaden the maximum flow capacity by all sides on the path minus
  3. The maximum cumulative flow
  4. Repeat the above steps until you can not find the augmenting path
1.2.2 Templates

Title: Luo Gu P3376 Network maximum flow

Description Title: If that, given a network diagram, and the source and sink, the network obtains its maximum flow.

Input formats:

The first row contains four positive integers N, M, S, T, respectively, the number of points, there are the number of edges, number source, sink point number.

Next M lines contains three positive integers ui, vi, wi, represents the i ui article there from edge to reach VI, the right side of wi (i.e., the side of the maximum flow rate wi)

Output format: one line containing a positive integer, is the maximum flow of the network.

Code:

//Edmonds-Karp
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5, maxm = 1e5+5, INF = 1e9+7;
int head[maxn], ver[maxm*2], edge[maxm*2], Next[maxm*2], tot;
void add(int x,int y,int z)
{
    ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}
int pre[maxn], incf[maxn], s, t, maxflow;
int n, m;
bool bfs()
{
    bool vis[maxn] = {};
    queue<int> Q;
    Q.push(s);incf[s] = INF;vis[s] = true;
    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i])
           if(edge[i])
           {
              int y = ver[i];
              if(vis[y]) continue;
              incf[y] = min(incf[x], edge[i]);
              pre[y] = i;
              Q.push(y), vis[y] = true;
              if( y == t ) return true;
           }
    }
    return false;
}
void update()
{
    int x = t;
    while(x!=s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow+=incf[t];
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    tot = 1;
    for(int i=1; i<=m; i++)
    {
        int ui, vi, wi;
        scanf("%d%d%d",&ui,&vi,&wi);
        add(ui, vi, wi);
    }
    while(bfs()) update();
    printf("%d", maxflow);
    return 0;
}

1.3 \ (Dinic \) algorithm

1.3.1 algorithm flow
  1. First \ (BFS \) , built layered graph , dividing node hierarchy , the depth of presence nodes \ (D \) array
  2. In the layered graph \ (DFS \) , looking for augmenting path, and updates the remaining capacity at the back (each point may flow out of a plurality of sides)
  3. Repeat the above steps until no augmenting path so far
1.3.2 Templates

Topic with 1.2.2

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005, maxm = 100005, INF = 1e9;
int head[maxn], ver[maxm<<1], edge[maxm<<1], Next[maxm<<1], tot;
int N, M, S, T, d[maxn];
void add(int x, int y, int z){
    ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}
bool bfs(){
    for(int i=1; i<=N; i++) d[i] = 0;
    queue<int> Q;
    Q.push(S), d[S] = 1;
    while(!Q.empty()){
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i]){
            int y = ver[i];
            if(edge[i] and !d[ver[i]]){
                d[y] = d[x] + 1;
                Q.push(y);
                if(y == T) return true;
            }
        }
    }
    return false;
}
int dfs(int x, int flow){
    if(x == T) return flow;
    int rest = flow, k;
    for(int i=head[x]; i and rest; i=Next[i])
        if(edge[i] and d[ver[i]] == d[x]+1){
            k = dfs(ver[i], min(rest, edge[i]));
            edge[i] -= k;
            edge[i^1] += k;
            rest -= k;
        }
    return flow - rest;
}
int main(){
    tot = 1;
    scanf("%d%d%d%d",&N,&M,&S,&T);
    for(int i=1; i<=M; i++){
        int x, y, z;
        scanf("%d%d%d",&x,&y,&z);
        add(x, y, z);
    }
    int maxflow = 0, flow = 0;
    while(bfs()) while(flow = dfs(S, INF)) maxflow += flow;
    printf("%d", maxflow);
    return 0;
}
1.3.3 Current Arc optimization

For this, I think the Internet a big brother put it very well, a little quote here.

Bowen Portal

Author: SDFZ-Floatiy

Source: CSDN

In fact, it is a very strong optimization

After each augmenting path can be seen as a "drained" this path, there will be no further increase since drained wide possible. But if every time scanning these "withered" side is a waste of time. Then we record it "squeeze" to that edge, and then the next time directly from this side to start augmenting, you can save a lot of time. This is the current arc optimization.

Specifically how to achieve it, copy, deposited into cur array to the head array of stars before the first chain, then each record "squeeze" where edges in the cur array.

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005, maxm = 100005, INF = 1e9;
int head[maxn], cur[maxn], ver[maxm<<1], edge[maxm<<1], Next[maxm<<1], tot;
int N, M, S, T, d[maxn];
void add(int x, int y, int z){
    ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}
bool bfs(){
    for(int i=1; i<=N; i++) d[i] = 0, cur[i] = head[i];
    queue<int> Q;
    Q.push(S), d[S] = 1;
    while(!Q.empty()){
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i]){
            int y = ver[i];
            if(edge[i] and !d[ver[i]]){
                d[y] = d[x] + 1;
                Q.push(y);
                if(y == T) return true;
            }
        }
    }
    return false;
}
int dfs(int x, int flow){
    if(x == T) return flow;
    int rest = flow, k;
    for(int i=cur[x]; i and rest; i=Next[i]){
        cur[x] = i;
        if(edge[i] and d[ver[i]] == d[x]+1){
            k = dfs(ver[i], min(rest, edge[i]));
            edge[i] -= k;
            edge[i^1] += k;
            rest -= k;
        }
    }
    return flow - rest;
}
int main(){
    tot = 1;
    scanf("%d%d%d%d",&N,&M,&S,&T);
    for(int i=1; i<=M; i++){
        int x, y, z;
        scanf("%d%d%d",&x,&y,&z);
        add(x, y, z);
    }
    int maxflow = 0, flow = 0;
    while(bfs()) while(flow = dfs(S, INF)) maxflow += flow;
    printf("%d", maxflow);
    return 0;
}

1.4 Cost Flow

Cost Flow fact, not difficult, nothing is more than a right side. Just 1.2 algorithm \ (bfs \) instead \ (spfa \) can be.

Title: Luo Gu P3381 minimum cost maximum flow

Title Description

If that, given a network diagram, and the source and sink, each side units is known maximum flow and traffic charges, which determine the maximum flow and minimum cost network in the case of maximum flow.

Input Format

The first row contains four positive integers N, M, S, T, respectively, the number of points, there are the number of edges, number source, sink point number.

Next M lines contains four integer ui, vi, wi, fi, denotes the i th ui from there to the edge and arriving at VI, the right side of wi (i.e., the side of the maximum flow rate Wi), per unit flow rate fee fi.

Output Format

One line containing two integers, followed by the maximum flow and minimum cost at maximum flow conditions.

Code

//Edmonds-Karp
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5005, maxm = 50005, INF = 1e9+7;
int head[maxn], ver[maxm<<1], edge[maxm<<1], Next[maxm<<1], cost[maxm<<1], tot;
void add(int x,int y,int z,int w)
{
    ver[++tot] = y, edge[tot] = z, cost[tot] = w, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, cost[tot] = -w, Next[tot] = head[y], head[y] = tot;
}
int pre[maxn], incf[maxn], dis[maxn], s, t, maxflow, ans;
int n, m;
bool spfa()
{
    bool vis[maxn] = {};
    queue<int> Q;
    Q.push(s);incf[s] = INF;vis[s] = true;
    for(int i=1; i<=n; i++) dis[i] = INF;
    dis[s] = 0;
    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i])
           if(edge[i])
           {
              int y = ver[i];
              if(dis[y] > dis[x]+cost[i])
              {
                  dis[y] = dis[x]+cost[i];
                  incf[y] = min(incf[x], edge[i]);
                  pre[y] = i;
                  if(!vis[y]) vis[y] = true, Q.push(y);
              }
           }
        vis[x] = false;
    }
    if(dis[t] == INF) return false;
    return true;
}
void update()
{
    int x = t;
    while(x!=s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow+=incf[t];
    ans+=dis[t]*incf[t];
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    tot = 1;
    for(int i=1; i<=m; i++)
    {
        int ui, vi, wi, fi;
        scanf("%d%d%d%d",&ui,&vi,&wi,&fi);
        add(ui, vi, wi, fi);
    }
    while(spfa()) update();
    printf("%d %d", maxflow, ans);
    return 0;
}

2 solution to a problem

2.1 POJ2455 \(Secret Milking Machine\)

The meaning of problems: given an undirected graph , the nodes Q \ (1 \) to the node \ (N \) a \ (T \) strip does not overlap paths, each path in the maximum value of the shortest side is How many.

Practice: half, maximum flow

Ideas: see "Maximum shortest side", apart from anything else, the first half of the answer.

After half maximum of the shortest side, the unwanted side (side is smaller than this value) is removed, to give a FIG.

This is easy to see, as long as less than found in the remaining figures \ (T \) does not overlap the path.

Consider the network flow, the capacity of each edge is set to \ (1 \) , traffic flows from an unlimited source.

Find the maximum flow to the sink, if greater than or equal \ (T \) , as evidenced by at least \ (T \) paths do not overlap may be to sink.

Code:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 305, maxm = 40005, INF = 2147483647;
int cur[maxn], head[maxn], ver[maxm<<1], edge[maxm<<1], Next[maxm<<1], tot;
int N, P, T, u[maxm], v[maxm], c[maxm];
int s, t, d[maxn];
void add(int x, int y, int z){
    ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = z, Next[tot] = head[y], head[y] = tot;
}
void Memset(){
    memset(head, 0, sizeof(head));
    memset(Next, 0, sizeof(Next));
    memset(ver, 0, sizeof(ver));
    memset(edge, 0, sizeof(edge));
    tot = 1;
}
bool bfs(){
    for(int i=1; i<=N; i++) d[i] = 0, cur[i] = head[i];
    queue<int> Q;
    Q.push(s), d[s] = 1;
    while(!Q.empty()){
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i]){
            int y = ver[i];
            if(edge[i] and !d[ver[i]]){
                d[y] = d[x] + 1;
                Q.push(y);
                if(y == t) return true;
            }
        }
    }
    return false;
}
int dfs(int x, int flow){
    if(x == t) return flow;
    int rest = flow, k;
    for(int i=cur[x]; i and rest; i=Next[i]){
        cur[x] = i;
        if(edge[i] and d[ver[i]] == d[x]+1){
            k = dfs(ver[i], min(rest, edge[i]));
            edge[i] -= k;
            edge[i^1] += k;
            rest -= k;
        }
    }
        
    return flow - rest;
}
bool check(int x){
    Memset();
    for(int i=1; i<=P; i++) if(c[i] <= x) add(u[i], v[i], 1);
    int maxflow = 0, flow = 0;
    while(bfs()) while(flow = dfs(s, INF)) maxflow += flow;
    return maxflow >= T;
}
int main(){
    scanf("%d%d%d",&N, &P, &T);
    int l = INF, r = 0;
    s=1, t=N;
    for(int i=1; i<=P; i++){
        scanf("%d%d%d",&u[i], &v[i], &c[i]);
        l = min(l, c[i]);
        r = max(r, c[i]);
    }
    while(l <= r){
        int mid = (l+r)>>1;
        if(check(mid)) r = mid-1;
        else l = mid+1;
    }
    printf("%d", r+1);
    return 0;
}

2.2 POJ2135 \(Farm Tour\)

The meaning of problems: given an undirected graph , the \ (1 \) departing to \ (N \) , to find the two do not overlap most short (minimum), and calculates their sum.

Practices: \ (SPFA \) , \ (Edmonds-Karp \)

Ideas: it is easy to think of how to build the side, directly in accordance with the meaning of the questions can be built side, the key is how to find the two non-overlapping shortest path.

With the experience of the previous question and found no overlap of the word, we should think of network flow.

In order to find the shortest path, nature is cost flow network flow.

In this case, since the subject of the request does not overlap, the capacity of each edge figure are \ (\ 1) , the cost is the length of this path.

Claim the subject and requires two paths, i.e., the flow rate of \ (2 \) , so that a new source and a sink, are connected to the \ (1 \) and \ (N \) , capacity \ (2 \) , capacity constraints, to ensure a maximum flow of the entire FIG \ (2 \) (since the maximum flow rate of all edges are figures \ (1 \) , to ensure a maximum flow \ (2 \) is there to ensure that the two augmenting path, ie two shortest path)

The minimum cost to output.

Code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1005, maxm = 20005, INF = 1e9;
int head[maxn], ver[maxm<<1], edge[maxm<<1], cost[maxm<<1], Next[maxm<<1], tot;
int N, M, s, t;
int incf[maxn], pre[maxn], dis[maxn], maxflow, ans;
bool vis[maxn];
void add(int x, int y, int z, int val){
    ver[++tot] = y, edge[tot] = z, cost[tot] = val, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, cost[tot] = -val, Next[tot] = head[y], head[y] = tot;
}
bool spfa(){
    for(int i=1; i<=N; i++) dis[i] = INF, vis[i] = false;
    queue<int> Q;
    Q.push(s);
    dis[s] = 0; incf[s] = INF; vis[s] = true;
    while(!Q.empty()){
        int x = Q.front(); Q.pop(); vis[x] = false;
        for(int i=head[x]; i; i=Next[i])
            if(edge[i]){
                int y = ver[i];
                if(dis[x] + cost[i] < dis[y]){
                    dis[y] = dis[x] + cost[i];
                    incf[y] = min(incf[x], edge[i]);
                    pre[y] = i;
                    if(!vis[y]) vis[y] = true, Q.push(y);
                }
            }
    }
    if(dis[t] == INF) return false;
    return true;
}
void update(){
    int x = t;
    while(x != s){
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
    }
    maxflow += incf[t];
    ans += incf[t]*dis[t];
}
int main(){
    scanf("%d%d",&N,&M);
    tot = 1, s = N+1, t = N+2;
    for(int i=1; i<=M; i++){
        int x, y, cost;
        scanf("%d%d%d",&x,&y,&cost);
        add(x, y, 1, cost);
        add(y, x, 1, cost);
    }
    N += 2;
    add(s, 1, 2, 0);
    add(N-2, t, 2, 0);
    while(spfa()) update();
    printf("%d",ans);
    return 0;
}

2.3 POJ3680 $Intervals $

Meaning of the questions: given \ (N \) th open interval , each interval has a weight. Only allows a maximum of \ (K \) intervals overlap . Seeking maximum weights and interval.

Practices: \ (SPFA \) , \ (Edmonds-Karp \) , discrete

Thinking: This question is difficult to think, but to say how to build a plan.

All endpoints will be sorted sections, fitted to a straight line (similar to what number axis).

Then build a source in the forefront, to establish a meeting point at the very end.

The tap sequence before all sequentially connected to the rear side, except that the two edges connected to the source and sink, the capacity of the other side is unlimited, cost is 0.

That the two sides of the source and sink capacity is \ (K \) , 0 cost.

Above are well understood, the highlight came.

The original left and right end sections connected to a capacity of 1, to take the weight interval.

According to the above, you can do it yourself drawing a picture helps to understand.

It can be visually seen, if two intervals overlap (assumed to be the interval \ (A \) and \ (B \) ), then the interval \ (A \) must section \ (B \) endpoint.

It can be speculated if the interval \ (A \) and (X \) \ have overlapping intervals, the interval \ (A \) there must be \ (X \) endpoints of other sections.

Here, can be found to control the \ (A \) up to the number of overlapping sections, only need to control flow through the section \ (A \) flow rate, and the interval \ (A \) overlapping interval is not greater than the number of traffic because each flowing through a range of other, \ (a \) flow rate range will be reduced by one.

This is also the aforementioned source to limit the flow of Meeting Point is \ (K \) reasons.

According to the above construction was then view a running cost can stream (note that the cost of seeking the maximum, thus the interval may take the opposite of weights, sets of templates)

Code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1505, maxm = 2005, INF = 1e9+7;
int head[maxn], ver[maxm<<1], edge[maxm<<1], cost[maxm<<1], Next[maxm<<1], tot;
int N, K, Left[maxn], Right[maxn], lenth[maxn], seq[maxn<<1], key[maxn<<1];
int s, t, ans, incf[maxn], pre[maxn], dis[maxn];
void add(int x, int y, int z, int val){
    ver[++tot] = y, edge[tot] = z, cost[tot] = val, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, cost[tot] = -val, Next[tot] = head[y], head[y] = tot;
}
bool spfa()
{
    bool vis[maxn] = {};
    queue<int> Q;
    Q.push(s);incf[s] = INF;vis[s] = true;
    for(int i=1; i<=t; i++) dis[i] = INF;
    dis[s] = 0;
    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for(int i = head[x]; i; i=Next[i])
           if(edge[i])
           {
              int y = ver[i];
              if(dis[y] > dis[x]+cost[i])
              {
                  dis[y] = dis[x]+cost[i];
                  incf[y] = min(incf[x], edge[i]);
                  pre[y] = i;
                  if(!vis[y]) vis[y] = true, Q.push(y);
              }
           }
        vis[x] = false;
    }
    if(dis[t] == INF) return false;
    return true;
}
void update()
{
    int x = t;
    while(x!=s)
    {
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i^1] += incf[t];
        x = ver[i^1];
        
    }
    ans+=dis[t]*incf[t];
}
int main(){
//  freopen("eeeeeee.txt","w",stdout);
    int G;
    scanf("%d",&G);
    while(G--){
        tot = 1; ans = 0;
        memset(head, 0, sizeof(head));
        memset(Next, 0, sizeof(Next));
        scanf("%d%d",&N,&K);
        for(int i=1; i<=N; i++){
            int l, r;
            scanf("%d%d%d",&Left[i], &Right[i],&lenth[i]);
            if(Left[i] > Right[i]) swap(Left[i], Right[i]);
            seq[i] = Left[i], seq[i+N] = Right[i];
        }
        sort(seq+1, seq+2*N+1);
        int rak = 0;
        for(int i=1; i<=2*N; i++)
            if(seq[i] != seq[i-1]) key[++rak] = seq[i];
        for(int i=1; i<=N; i++){
            for(int j=1; j<=rak; j++){
                if(Left[i] == key[j]) Left[i] = j;
                if(Right[i] == key[j]) Right[i] = j;
            }
        }
        s = rak+1, t = rak+2;
        add(s, 1, K, 0); add(rak, t, K, 0);
        for(int i=1; i<rak; i++) add(i, i+1, INF, 0);
        for(int i=1; i<=N; i++) add(Left[i], Right[i], 1, -lenth[i]);
        while(spfa()) update();
        printf("%d\n", -ans);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/GDOI2018/p/11299976.html