网络流

(G=(V,E)):有向图,s:源点,t:汇点,边权:流量。不存在反向边(存在可以加点)。

可行流 (f):容量限制,流量守恒对于每个点流入流出相同(不考虑反向边)。

最大流:最大可行流。

残留网络:与可行流一一对应,由原图边和反向边组成,原图边,容量减流量,原图反向边,退流。

原网络的可行流加残留网络的可行流也是原网络的可行流。流量值相加。

增广路径:在残留网络里,沿着边权大于零的边走,如果能到达重点则称为增广路径。

若可行流没有增广路径,则该可行流为最大流。

割:把点集分成两个子集:(S),(T),(s∈S),(t∈T)。

割的容量:由 (S) 指向 (T) 的边权之和。(不考虑反向边)

割的流量:由 (S) 指向 (T) 的流量之和减去由 (T) 指向 (S) 的流量之和。

割的流量一定小于等于割的容量。

最大流小于等于最小割

最大流 (f) 的残留网络中不存在增广路。存在割的流量等于最大流的流量。

(EK) 算法:复杂度 (O(nm^2))。迭代,每次先找一条增广路,更新残留网络,求增广路径上容量的最小值,更新所有正向边减去 (k),所有反向边增加 (k),利用一个 (pre) 数组记录一下路径。

const int N = 1e3 + 10;
const int M = 2e4 + 10; //残留网络
const int inf = 1e8;

int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx; //f容量
int q[N], d[N], pre[N];//宽搜队列,记录从起点到当前点的容量最小值
bool st[N];

inline void add(int a, int b, int c){//维护残留网络
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;//容量
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;//反向边容量为0
}

inline bool bfs(){//bfs找增广路
    int hh = 0, tt = 0;
    memset(st, false, sizeof st);
    q[0] = S, st[S] = true, d[S] = inf;
    while(hh

(Dinic) 算法:复杂度 (O(n^2m))。

const int N = 1e4 + 10;
const int M = 2e5 + 10;
const int inf = 1e8;

int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx; //f容量
int q[N], d[N], cur[N];//优化

inline void add(int a, int b, int c){//维护残留网络
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;//容量
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;//反向边容量为0
}
//当前弧优化
//记录流满的边数,从下一条边开始枚举

inline bool bfs(){  //判断有无增广路,并建立分层图
    int hh = 0, tt = 0;
    memset(d, -1, sizeof d);
    q[0] = S, d[S] = 0, cur[S] = h[S];
    while (hh

用网络流解题,需要可行流与可行解一一对应。

在一个流网络里,所有最大可行流中费用的最小、最大值。

最小费用最大流:退费用,(SPFA)求一条源点到汇点的最短路,更新残留网络,((EK))。

const int N = 5e3 + 10;
const int M = 2e5 + 10;
const int inf = 1e8;

int n, m, S, T;
int h[N], e[M], f[M], w[M], ne[M], idx;
int q[N], d[N], pre[N], incf[N];
//记录推最短路,走到每个点的最大流量
bool st[N];

inline void add(int a, int b, int c, int d){
    e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++;
    e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++;
}

inline bool spfa(){
    int hh = 0, tt = 1;
    memset(d, 0x3f, sizeof d);
    memset(incf, 0, sizeof incf);
    q[0] = S, d[S] = 0, incf[S] = inf;
    while(hh != tt){
        int t = q[hh ++];
        if(hh == N) hh = 0;
        st[t] = false;
        for(int i = h[t]; ~ i; i = ne[i]){
            int ver = e[i];
            if(f[i] && d[ver] > d[t] + w[i]){
                d[ver] = d[t] + w[i];
                pre[ver] = i;
                incf[ver] = min(f[i], incf[t]);
                if(!st[ver]){
                    q[tt ++] = ver;
                    if(tt == N) tt = 0;
                    st[ver] = true;
                }
            }
        }
    }
    return incf[T] > 0;
}

inline void EK(int &flow, int &cost){
    flow = cost = 0;
    while(spfa()){
        int t = incf[T];
        flow += t, cost += t * d[T];
        for(int i = T; i != S; i = e[pre[i] ^ 1]){
            f[pre[i]] -= t, f[pre[i] ^ 1] += t;
        }
    }
}

signed main(){
    read(n), read(m), read(S), read(T);
    memset(h, -1, sizeof h);
    while(m --){
        int a, b, c, d;
        read(a), read(b), read(c), read(d);
        add(a, b, c, d);
    }
    int flow, cost;
    EK(flow, cost);
    print(flow), cout << " ", print(cost);
    return 0;
}

Original: https://www.cnblogs.com/William-Sg/p/16406987.html
Author: Altwilio
Title: 网络流

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/605269/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球