其他分享
首页 > 其他分享> > 网络流

网络流

作者:互联网

网络流

1. 网络流原理

原理

1.1 流网络

在这里插入图片描述

1.2 可行流

∣ f ∣ = ∑ ( s , v ) ∈ E f ( s , v ) − ∑ ( v , s ) ∈ E f ( v , s ) |f| = \sum _{(s, v) \in E} f(s, v) - \sum _{(v, s) \in E} f(v, s) ∣f∣=(s,v)∈E∑​f(s,v)−(v,s)∈E∑​f(v,s)

一般来说,后一项为0。

在这里插入图片描述

1.3 残留网络

c ′ ( u , v ) = { c ( u , v ) − f ( u , v ) ( u , v ) ∈ E f ( v , u ) ( v , u ) ∈ E c'(u, v) = \begin{cases} c(u, v) - f(u, v) \quad \quad (u, v) \in E \\ f(v, u) \quad \quad (v, u) \in E \end{cases} c′(u,v)={c(u,v)−f(u,v)(u,v)∈Ef(v,u)(v,u)∈E​

也就是说残留网络的反向边容量 等于 原图的正向边的流量,残留网络的正向边的容量 等于 原图边的容量减去流量。

在这里插入图片描述


1.4 增广路径

在这里插入图片描述

1.5 割


首先由如下前置知识,对于 f ( X , Y ) = ∑ u ∈ X ∑ v ∈ Y f ( u , v ) − ∑ v ∈ X ∑ u ∈ Y f ( u , v ) f(X, Y) = \sum _ {u \in X} \sum _ {v \in Y} f(u, v) - \sum _ {v \in X} \sum _ {u \in Y} f(u, v) f(X,Y)=∑u∈X​∑v∈Y​f(u,v)−∑v∈X​∑u∈Y​f(u,v):
f ( X , Y ) = − f ( Y , X ) f ( X , X ) = 0 f ( Z , X ∪ Y ) = f ( Z , X ) + f ( Z , Y ) 前 提 : X ∩ Y = ∅ f ( X ∪ Y , Z ) = f ( X , Z ) + f ( Y , Z ) 前 提 : X ∩ Y = ∅ f(X, Y) = -f(Y, X) \\\\ f(X, X) = 0 \\\\ f(Z, X \cup Y) = f(Z, X) + f(Z, Y) \quad \quad 前提:X \cap Y = \empty \\\\ f(X \cup Y, Z) = f(X, Z) + f(Y, Z) \quad \quad 前提:X \cap Y = \empty f(X,Y)=−f(Y,X)f(X,X)=0f(Z,X∪Y)=f(Z,X)+f(Z,Y)前提:X∩Y=∅f(X∪Y,Z)=f(X,Z)+f(Y,Z)前提:X∩Y=∅
因为 S ∪ T = V , S ∩ T = ∅ S \cup T = V, S \cap T = \empty S∪T=V,S∩T=∅,因此有: f ( S , V ) = f ( S , S ) + f ( S , T ) f(S, V) = f(S, S) + f(S, T) f(S,V)=f(S,S)+f(S,T),所以:
f ( S , T ) = f ( S , V ) − f ( S , S ) = f ( S , V ) = f ( { s } , V ) + f ( S − { s } , V ) = f ( { s } , V ) + f ( S ′ , V ) = f ( { s } , V ) = ∣ f ∣ f(S, T) = f(S, V) - f(S, S) \\\\ = f(S, V) \\\\ = f(\{s\}, V) + f(S-\{s\}, V) \\\\ = f(\{s\}, V) + f(S', V) \\\\ = f(\{s\}, V) = |f| f(S,T)=f(S,V)−f(S,S)=f(S,V)=f({s},V)+f(S−{s},V)=f({s},V)+f(S′,V)=f({s},V)=∣f∣
上式中 S ′ = S − { s } S'= S-\{s\} S′=S−{s},因为S'中不包含源点和汇点,因为流量守恒,所以 f ( S ′ , V ) = 0 f(S', V) = 0 f(S′,V)=0。形式化证明:
f ( S ′ , V ) = ∑ u ∈ S ′ ∑ v ∈ V f ( u , v ) − ∑ u ∈ S ′ ∑ v ∈ V f ( v , u ) = ∑ u ∈ S ′ ( ∑ v ∈ V f ( u , v ) − ∑ v ∈ V f ( v , u ) ) = 0 f(S', V) = \sum _ {u \in S'} \sum _ {v \in V} f(u, v) - \sum _ {u \in S'} \sum _ {v \in V} f(v, u) \\\\ = \sum _ {u \in S'} \Big( \sum _ {v \in V}f(u, v) - \sum _ {v \in V} f(v, u) \Big) = 0 f(S′,V)=u∈S′∑​v∈V∑​f(u,v)−u∈S′∑​v∈V∑​f(v,u)=u∈S′∑​(v∈V∑​f(u,v)−v∈V∑​f(v,u))=0

∣ f ∣ = f ( S , T ) = ∑ u ∈ S ∑ v ∈ T f ( u , v ) − ∑ v ∈ S ∑ u ∈ T f ( u , v ) ≤ ∑ u ∈ S ∑ v ∈ T f ( u , v ) ≤ ∑ u ∈ S ∑ v ∈ T c ( u , v ) = c ( S , T ) |f| = f(S, T) = \sum _ {u \in S} \sum _ {v \in T} f(u, v) - \sum _ {v \in S} \sum _ {u \in T} f(u, v) \\\\ \le \sum _ {u \in S} \sum _ {v \in T} f(u, v) \\\\ \le \sum _ {u \in S} \sum _ {v \in T} c(u, v) = c(S, T) ∣f∣=f(S,T)=u∈S∑​v∈T∑​f(u,v)−v∈S∑​u∈T∑​f(u,v)≤u∈S∑​v∈T∑​f(u,v)≤u∈S∑​v∈T∑​c(u,v)=c(S,T)


最大流最小割定理

(1)->(2)

(3)->(1)

(2)->(3)

在这里插入图片描述

所以有:
∣ f ∣ = f ( S , T ) = ∑ u ∈ S ∑ v ∈ T f ( u , v ) − ∑ u ∈ S ∑ v ∈ T f ( v , u ) = ∑ u ∈ S ∑ v ∈ T f ( u , v ) = ∑ u ∈ S ∑ v ∈ T c ( u , v ) = c ( S , T ) |f| = f(S, T) \\\\ = \sum _ {u \in S} \sum _ {v \in T} f(u, v) - \sum _ {u \in S} \sum _ {v \in T} f(v, u) \\\\ = \sum _ {u \in S} \sum _ {v \in T} f(u, v) \\\\ = \sum _ {u \in S} \sum _ {v \in T} c(u, v) \\\\ = c(S, T) ∣f∣=f(S,T)=u∈S∑​v∈T∑​f(u,v)−u∈S∑​v∈T∑​f(v,u)=u∈S∑​v∈T∑​f(u,v)=u∈S∑​v∈T∑​c(u,v)=c(S,T)
证毕!

算法思想:FF

while (存在增广路) {
    (1) 找增广路;
    (2) 更新残留网络;
}

2. AcWing上的网络流题目

AcWing 2171. EK求最大流

问题描述

在这里插入图片描述

分析

代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010, M = 20010, INF = 1e8;

int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;  // f: 记录边权(容量)
int q[N];  // bfs使用的队列
int d[N];  // 从S到当前点边权最小值
int pre[N];  // 到达当前点对应的正向边
bool st[N];  // 遍历图使用到的判重数组

// 加入原图中的边,以及反向边
void add(int a, int b, int c) {
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;  // 加入(a, b, c)
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;  // 加入(b, a, 0)
}

// 判断残留网络是否存在增广路径 以及 求解增广路径
bool bfs() {
    
    memset(st, 0, sizeof st);
    
    int hh = 0, tt = -1;
    q[++tt] = S, st[S] = true, d[S] = INF;
    while (hh <= tt) {
        int t = q[hh++];
        for (int i = h[t]; ~i; i = ne[i]) {
            int ver = e[i];
            if (!st[ver] && f[i]) {  // 未被遍历过,并且边权不为0
                st[ver] = true;
                d[ver] = min(d[t], f[i]);
                pre[ver] = i;
                if (ver == T) return true;
                q[++tt] = ver;
            }
        }
    }
    return false;
}

int EK() {
    int r = 0;  // 最大流对应数值
    while (bfs()) {
        r += d[T];
        for (int i = T; i != S; i = e[pre[i] ^ 1]) {  // e[pre[i] ^ 1]是i的前驱点
            f[pre[i]] -= d[T];  // 正向边减去k=d[T]
            f[pre[i] ^ 1] += d[T];  // 反向边加上k=d[T]
        }
    }
    return r;
}

int main() {
    
    scanf("%d%d%d%d", &n, &m, &S, &T);
    memset(h, -1, sizeof h);
    while (m--) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }
    
    printf("%d\n", EK());
    
    return 0;
}

标签:可行,增广,int,sum,网络,残留
来源: https://blog.csdn.net/weixin_42638946/article/details/120508463