「网络流」学习笔记

给出一个有向图,有源点\(S\)和汇点\(T\)。每条边有一个容量,现在要从源点开始流,每条边不能超过其容量。在流的过程中有许多问题,最大流、费用流等等。许多问题都可以通过网络流来建模。

最大流

最大流问题就是问从源点出发流到汇点,汇点最多能流到多少。

概念

反向边

如果直接流,有时不会是最优的。(不想传图片了qaq)

此时我们考虑加入反向边。考虑从\(u\)流到\(v\)的流量为\(f\),那么等价于从\(v\)流到\(u\)的流量为\(-f\)

增广路

加入反向边之后每找到一条可流的路就去流,直到无法再增加。称这样一条可行的路为增广路。只要不断寻找增广路即可求出最大流。

残量网络

定义:残量=容量-流量

这样增广路就对应残量网络中一条边权全部为正的路径。增广路增广的值就是这条路径中残量的最小值。

设一条边容量为\(c\),流量为\(f\)。则其残量为\(c-f\)

这条边的反向边流量为\(-f\),其残量应为\(f\),故反向边的容量应为\(0\)

Dinic算法

每一轮只考虑残量>0的边,进行\(BFS\)分层,每一次规定增广路的边必须连接相邻两个层。这样做的意义是每次只找确定长度的增广路对流量的贡献,这样最多进行\(n\)次分层即可完成整个最大流的求解。

分层之后\(DFS\)找增广路。这里进行多路增广,也就是一次DFS找出多条增广路一起增广。

每一次在\(DFS\)的过程中传入参数\(a\)表示当前点出发的最大流量,在回溯时判断从这一步走能否找到增广路,并返回找到的增广路的贡献更新。

当前弧优化

在分层图确定的情况下,每个点只\(DFS\)一次。因此一个点出发的每一条边都不需要重复搜索。由于边的顺序是确定的,用一个数组记录前多少条边已经搜过了,避免重复搜索。

\(Code\)

/*DennyQi 2019*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 10010;
const int M = 100010;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
inline int read(){
    int x(0),w(1); char c = getchar();
    while(c^'-' && (c<'0' || c>'9')) c = getchar();
    if(c=='-') w = -1, c = getchar();
    while(c>='0' && c<='9') x = (x<<3)+(x<<1)+c-'0', c = getchar(); 
    return x*w;
}
int n,m,S,T,ans,x,y,z,cur[N],h,t,q[N],lv[N];
int head[N],nxt[M<<1],to[M<<1],c[M<<1],f[M<<1],cnte;
inline int corres(int i){
    return (i&1) ? i+1 : i-1;
}
inline void add(int u, int v, int C, int F){
    to[++cnte] = v;
    c[cnte] = C;
    f[cnte] = F;
    nxt[cnte] = head[u];
    head[u] = cnte;
}
inline bool BFS(){
    memset(lv,0,sizeof(lv));
    h = t = 0;
    int u;
    lv[S] = 1;
    q[++t] = S;
    while(h < t){
        u = q[++h];
        for(int i = head[u]; i; i = nxt[i]){
            if(lv[to[i]] || c[i]-f[i]==0) continue;
            lv[to[i]] = lv[u]+1;
            q[++t] = to[i];
        }
    }
    return lv[T];
}
int DFS(int u, int a){
    if(u == T || !a) return a;
    int res=0, F;
    for(int& i = cur[u]; i; i = nxt[i]){
        if(lv[to[i]]==lv[u]+1 && c[i]-f[i]>0){
            F = DFS(to[i],min(a,c[i]-f[i]));
            a -= F;
            res += F;
            f[i] += F, f[corres(i)] -= F;
            if(!a) break;
        }
    }
    return res;
}
inline void Dinic(){
    while(BFS()){
        for(int i = 1; i <= n; ++i) cur[i] = head[i];
        ans += DFS(S,INF);
    }
}
int main(){
    // freopen("file.in","r",stdin);
    n = read(), m = read(), S = read(), T = read();
    for(int i = 1; i <= m; ++i){
        x = read(), y = read(), z = read();
        add(x,y,z,0);
        add(y,x,0,0);
    }
    Dinic();
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qixingzhi/p/11293648.html
今日推荐