Summary of Network Flow Algorithms

Keywords: network REST

Summary of Network Flow Algorithms

Maximum flow algorithm

The main requirement of this algorithm is that in a directed graph, there is a maximum flow on each edge, and the maximum flow from the source point to the sink point is obtained. Generally, there are several algorithms to solve this kind of problem.

EK algorithm of augmented path

The main idea of this algorithm is very simple, that is, bfs is constantly looking for augmented paths and adding traffic to them until augmented paths can not be found. At this time, the flow from the source point is the maximum flow. Notice the concept of counter-flow, i.e. flow[u][v]=flow[v][u]
The upper limit of time complexity of the algorithm is O(V_E2), but this complexity is not generally achieved.
The following code is attached directly:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=1e+9;
const int maxn=200+10;
int c[maxn][maxn],f[maxn][maxn],p[maxn],pre[maxn],d[maxn<<4];
int main(){
    int i,j,k,m,n;
    int x,y,z;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        c[x][y]+=z;
    }
    int flag=1;
    while(flag){
        flag=0;
        memset(p,0,sizeof(p));
        int s=0,t=1;d[1]=1;pre[1]=0;p[1]=1;
        while(s<t){
            s++;x=d[s];
            for(i=1;i<=n;i++)
                if(!p[i] && (c[x][i]>f[x][i] || f[i][x]>0)){
                    p[i]=1;
                    d[++t]=i;
                    pre[i]=x;
                    if(i==n){
                        flag=1;
                        break;
                    }
                }
            if(flag)break;
        }
        if(!flag)break;
        t=n;int min=INF;
        while(pre[t]){
            x=pre[t];
            y=t;
            if(c[x][y]>f[x][y] && c[x][y]-f[x][y]<min)
                min=c[x][y]-f[x][y];
            else if(f[y][x]>0 && f[y][x]<min)
                min=f[y][x];
            t=pre[t];
        }
        t=n;
        while(pre[t]){
            x=pre[t];
            y=t;
            if(c[x][y]>f[x][y])
                f[x][y]+=min;
            else if(f[y][x]>0)
                f[y][x]-=min;
            t=pre[t];
        }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=f[1][i];
    printf("%d\n",ans);
    return 0;
}

dinic algorithm

Unlike EK algorithm, dinic algorithm needs to do bfs on the digraph once at a time, layering the graph and getting the layers of each point on the graph. dfs is used to search the augmented road, and the augmented road can only go from one layer to the next. If there is no augmented path, repeat the above process and re-lay the map until the augmented path can not be found.
The theoretical upper limit of the time complexity of the algorithm is O(n2m), but similarly, it is generally not enough. Even when dinic algorithm is used for bipartite graph matching, the complexity can reach O(n m).
Attach the code below:

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=1e9;
const int maxm=1e5+10;
const int maxn=1e4+10;
int nex[maxm<<1],beg[maxm<<1],to[maxm<<1],flow[maxm<<1],q[maxn],lev[maxn];
int e=1,n;
inline int read(){
    int x=0,flag=1;
    char ch=getchar();
    while(!isdigit(ch) && ch!='-')ch=getchar();
    if(ch=='-')flag=-1,ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*flag;
}
inline void add(int x,int y,int z){
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    flow[e]=z;
}
int bfs(int s,int t){
    int f=0,l=1,i;
    memset(lev,0,sizeof(lev));
    lev[s]=1;
    q[1]=s;
    while(f<l){
        f++;
        int x=q[f];
        if(x==t)return 1;
        for(i=beg[x];i;i=nex[i])
            if(!lev[to[i]] && flow[i]>0){
                lev[to[i]]=lev[x]+1;
                q[++l]=to[i];
            }
    }
    return 0;
}
int dfs(int x,int goal,int maxflow){
    int i;
    if(x==goal)
        return maxflow;
    for(i=beg[x];i;i=nex[i])
        if(flow[i]>0 && lev[x]+1==lev[to[i]]){
            int tmp=dfs(to[i],goal,min(maxflow,flow[i]));
            if(tmp>0){
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                return tmp;
            }
        }
    return 0;
}
int main(){
    int i,j,k,m;
    int x,y,z,s,t;
    n=read();m=read();s=read();t=read();
    for(i=1;i<=m;i++){
        x=read();y=read();z=read();
        add(x,y,z);
        add(y,x,0);
    }
    int ans=0;
    while(bfs(s,t))
        ans+=dfs(s,t,INF);
    printf("%d\n",ans);
    return 0;
}

ISAP algorithm

ISAP algorithm is optimized on the basis of dinic algorithm. Dinic algorithm needs to lay the residual traffic multiple times, while ISAP only needs to do one time, or even you can not lay the pretreatment (the code below does not lay the pretreatment). When dinic algorithm encounters an augmented path that does not satisfy the conditions, the residual traffic will be re-stratified, while ISAP will reset level[x] to min(level[i])+1, where I to X has a directed edge.
But this optimization is not enough. The greatest optimization of ISAP comes from GAP optimization.
GAP optimization is to see whether there are faults in the residual network (that is, any of the nodes do not belong to a certain layer), if there is one, it can exit directly.
The optimization of ISAP is very obvious. Without O 2 optimization, the maximum data of Luogu template problem is only about 80 ms, while the dinic above needs about 900 Ms.
Attach the code below:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e4+10;
const int maxm=2e5+10;
int flow[maxm],gap[maxn],dis[maxn],to[maxm],beg[maxm],nex[maxm];
int e=1,n,m,s,t;
void add(int x,int y,int z){
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    flow[e]=z;
}
int isap(int x,int f){
    if(x==t)return f;
    int res=f,i;
    for(i=beg[x];i;i=nex[i])
        if(flow[i]>0 && dis[x]==dis[to[i]]+1){
            int minflow=isap(to[i],min(res,flow[i]));
            flow[i]-=minflow;
            flow[i^1]+=minflow;
            res-=minflow;
            if(!res)return f;
        }
    if(!(--gap[dis[x]]))dis[s]=n;
    gap[++dis[x]]++;
    return f-res;
}
int main(){
    int i,x,y,w;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&w);
        add(x,y,w);
        add(y,x,0);
    }
    int maxflow=0;
    for(gap[0]=n;dis[s]<n;)maxflow+=isap(s,1e9);
    printf("%d\n",maxflow);
    return 0;
}

Minimum Cost Maximum Flow

This kind of problem adds a cost parameter on the basis of the maximum flow problem, requiring the minimum cost on the basis of the maximum flow. Find out the flow and cost at this time.
To solve this kind of problem, EK and spfa are usually combined.
The main idea of this algorithm is to use spfa to find the path with the least cost on the basis of EK augmented path algorithm, and the rest are basically the same as EK algorithm.
Attach the code below:

#include<stdio.h>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5e4+10;
const int INF=1e+9;
int to[maxn],nex[maxn],beg[maxn],c[maxn],w[maxn],pre[maxn],dis[maxn],vis[maxn],q[maxn<<3];
int n,e=1,m,s,t,maxflow;
inline int read(){
    int flag=1,x=0;
    char ch=getchar();
    while(!isdigit(ch) && ch!='-')ch=getchar();
    if(ch=='-')flag=-1,ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return flag*x;
}
void add(register int x,register int y,register int flow,register int cost){
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    c[e]=flow;
    w[e]=cost;
}
int Spfa(){
    for(register int i=1;i<=n;i++)dis[i]=INF;
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    int f=0,l=1;
    q[1]=s;dis[s]=0;vis[s]=1;pre[s]=s;
    while(f<l){
        f++;
        int k=q[f];
        vis[k]=0;
        for(register int i=beg[k];i;i=nex[i]){
            int tmp=to[i];
            if(c[i] && dis[tmp]>dis[k]+w[i]){
                pre[tmp]=i;
                dis[tmp]=dis[k]+w[i];
                if(!vis[tmp]){
                    vis[tmp]=1;
                    q[++l]=tmp;
                }
            }
        }
    }
    return !(dis[t]==INF);
}
int MCMF(){
    int cost=0;
    while(Spfa()){
        int d=INF;
        for(register int i=t;i!=s;i=to[pre[i]^1])
            d=min(d,c[pre[i]]);
        for(register int i=t;i!=s;i=to[pre[i]^1]){
            c[pre[i]]-=d;
            c[pre[i]^1]+=d;
            cost+=w[pre[i]]*d;
        }
        maxflow+=d;
    }
    return cost;
}
int main(){
    int x,y,flow,cost;
    n=read();m=read();s=read();t=read();
    for(register int i=1;i<=m;i++){
        x=read();y=read();flow=read();cost=read();
        add(x,y,flow,cost);
        add(y,x,0,-cost);
    }
    int mincost=MCMF();
    printf("%d %d\n",maxflow,mincost);
    return 0;
}

Posted by abionifade on Thu, 06 Jun 2019 15:52:37 -0700