ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

网络流

2021-09-27 15:05:27  阅读:202  来源: 互联网

标签:可行 增广 int sum 网络 残留


网络流

1. 网络流原理

原理

1.1 流网络

  • 是一个有向图G=(V, E),可以存在环。该有向图中存在一个源点s和一个汇点t。边上的权重被称为容量c

  • 如下图就是一个流网络:

在这里插入图片描述

1.2 可行流

  • 可行流f表示满足一定条件的网络流。需要满足如下两个条件:

    • (1)容量限制: 0 ≤ f ( u , v ) ≤ c ( u , v ) 0 \le f(u, v) \le c(u, v) 0≤f(u,v)≤c(u,v),其中 f ( u , v ) 、 c ( u , v ) f(u, v)、c(u, v) f(u,v)、c(u,v) 分别表示从uv的流量和容量。

    • (2)流量守恒: ∀ x ∈ V / { s , t } , ∑ ( u , x ) ∈ E f ( u , x ) = ∑ ( x , v ) ∈ E f ( x , v ) \forall x \in V/\{s, t\}, \sum _{(u, x) \in E} f(u, x) = \sum _{(x, v) \in E} f(x, v) ∀x∈V/{s,t},∑(u,x)∈E​f(u,x)=∑(x,v)∈E​f(x,v),即除了源点和汇点之外,流入任意点x的流量等于流出该点的流量。

  • 可行流f的大小用|f|表示,表示从源点s流向其他点的流量。公式表示为:

∣ 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。

  • 最大流:指的是网络G的最大可行流(即对应的|f|最大)。

  • 如下图红色标出的是一个可行流,同时也是一个最大流:

在这里插入图片描述

  • 一个网络可能会有很多可行流(甚至无穷多个),但是最大流只有一个。

1.3 残留网络

  • 残留网络是针对图G的某一个可行流f而言的,记为 G f G_f Gf​ 。残留网络和可行流是一一对应的。

  • 残留网络记为 G f = ( V f , E f ) G_f = (V_f, E_f) Gf​=(Vf​,Ef​),其中 V f = V V_f = V Vf​=V, E f = E ∪ E 对 应 的 所 有 反 向 边 E_f = E \cup E对应的所有反向边 Ef​=E∪E对应的所有反向边。残留网络也是一个流网络,各个边对应的容量定义如下:

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​

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

  • 上面例子可行流f对应的残留网络如下图(蓝边是原图中存在的边,红边是反向边):

在这里插入图片描述


  • 给定一个流网络G,对于G的一个可行流f,我们可以得到一个残留网络 G f G_f Gf​,若该残留网络存在一个可行流f',则有:f+f'是原图G的一个可行流。且|f+f'| = |f| + |f'|

  • 这里定义的两个可行流相加:每条边对应的权值相加,如果f'对应边的方向和f中对应边的方法相同,则将f'中对应边累加到f边中;如果方向不同,则让f中对应的边减去f'中对应边的权值。

  • 上述结论的证明:需要证明两点:(1)容量限制;(2)流量守恒;

  • (1)容量限制:

    • 如果两个可行流中边的方向相同,则 0 ≤ f ′ ( u , v ) ≤ c ′ ( u , v ) = c ( u , v ) − f ( u , v ) 0 \le f'(u, v) \le c'(u, v) = c(u, v) - f(u, v) 0≤f′(u,v)≤c′(u,v)=c(u,v)−f(u,v),所以 0 ≤ f ′ ( u , v ) + f ( u , v ) ≤ c ( u , v ) 0 \le f'(u, v) + f(u, v) \le c(u, v) 0≤f′(u,v)+f(u,v)≤c(u,v);(此时原图中的边方向是(u, v));

    • 如果两个可行流中边的方向不同,则 0 ≤ f ′ ( u , v ) ≤ c ′ ( u , v ) = f ( v , u ) ≤ c ( v , u ) 0 \le f'(u, v) \le c'(u, v) = f(v, u) \le c(v, u) 0≤f′(u,v)≤c′(u,v)=f(v,u)≤c(v,u),所以 0 ≤ f ( v , u ) − f ′ ( u , v ) ≤ c ( v , u ) 0 \le f(v, u) - f'(u, v) \le c(v, u) 0≤f(v,u)−f′(u,v)≤c(v,u);(此时原图中的边方向是(v, u));

  • (2)流量守恒:考虑f或者f'中的某个点,因为在两个图中原来是流量守恒的,因此相加后流量也是守恒的。

  • 最后还要证明|f+f'| = |f| + |f'|,根据定义:可行流的流量指的是从源点流出的流量大小,因此等式成立。

1.4 增广路径

  • 在残留网络中,从源点s出发,沿着容量大于零的边,如果能到达汇点t,那么这条路径就被称为增广路径。

  • 上面的例子中对应的残留网络不存在增广路径。下面的例子存在一个增广路径:

在这里插入图片描述

  • 一个增广路径其实就是指:一个最简单的流量大于零的可行流。

  • 有如下结论:如果可行流f是最大流,则f对应的残留网络中不存在增广路径。

  • 可以使用反证法证明:如果可行流f是最大流,并且f对应的残留网络中存在增广路径。因为增广路径本质上是残留网络中一个流量大于零的可行流,记为f',由上面的讲解可知f+f'是原图的一个更大的可行流,因此推出f不是最大流,矛盾。所以假设不成立,原结论成立。

  • 那现在存在一个问题:上述结论反过来是否成立呢?即:若原图的一个可行流f对应的残留网络中不存在增广路径,是否可以推出f是最大流呢?结论是可以推出。这个结论的证明就需要借助下面的概念。

1.5 割

  • 定义:将点集V分成不重不漏的两个子集S、T,即 S ∩ T = ∅ , S ∪ T = V S \cap T = \empty, S \cup T = V S∩T=∅,S∪T=V ,且 s ∈ S , t ∈ T s \in S, t \in T s∈S,t∈T,则[S、T]称为原图的一个割。

  • 割的容量:原图中所有从S指向T的容量之和,即 c ( S , T ) = ∑ u ∈ S ∑ v ∈ T c ( u , v ) c(S, T) = \sum _{u \in S} \sum _{v \in T} c(u, v) c(S,T)=∑u∈S​∑v∈T​c(u,v)。最小割:指的是容量最小对应的割。

  • 割的流量:原图对应的可行流f中,从ST的流量之和 减去 从TS的流量之和,即 f ( S , T ) = ∑ u ∈ S ∑ v ∈ T f ( u , v ) − ∑ v ∈ S ∑ u ∈ T f ( u , v ) 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) f(S,T)=∑u∈S​∑v∈T​f(u,v)−∑v∈S​∑u∈T​f(u,v)。


  • 对于任意原图的可行流f,任意割[S, T],有|f| = f(S, T)。证明如下:

首先由如下前置知识,对于 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,任意割[S, T],有|f| <= 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 ) |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)可行流f是最大流;

    • (2)可行流f的残留网络中不存在增广路;

    • (3)存在某个割[S, T],有|f| = c(S, T)

  • 接着是上述定理的证明,这里证明(1)可以推出(2),(2)可以推出(3),(3)可以推出(1)即可。

(1)->(2)

  • 1.4中已经使用反证法证明了。

(3)->(1)

  • 已知:存在某个割[S, T],有|f| = c(S, T),需要证明f是最大流。

  • 最大流 <= c(S, T) = |f|,又因为 最大流 >= |f|,因此f是最大流。

  • 另外最大流等于最小割,这是因为:最小割 <= c(S, T) = |f| <= 最大流,且 最小割 >= 最大流。

(2)->(3)

  • 我们的思路是构造一个割,使得割的容量等于可行流的流量。构造方式如下:

  • S:在 G f G_f Gf​ 中,从源点s出发,沿着容量大于0的边能够走到的所有点的集合。因为不存在增广路,所以汇点t一定不属于S。

  • T:T = V - S。汇点t属于T。

  • 此时[S, T]是一个割,下面要验证从该可行流f对应的残留网络构造的割的容量是否等于|f|。考虑原图中S指向T的边,则这些边上的流量一定等于边上的容量,即f(x, y) = c(x, y), x ∈ S , y ∈ T x \in S, y \in T x∈S,y∈T,因为这些边在残留网络中一定为0;考虑从T指向S的边,这些边上的流量一定为0,如果不为0的话,意味着对应的残留网络中会有一条从S指向T的反向边,且边权不为0,和我们的构造方式矛盾。如下图:

在这里插入图片描述

所以有:
∣ 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) 更新残留网络;
}
  • 我们维护的是残留网络,每次在残留网络中如果能够找到一条增广路径的话,如果该增广路径上边权最小值为k,则让该路径上的所有正向边-k,所有反向边+k,可行流的流量+k

  • 为了方便维护,我们让残留网络的正向边、反向边编号分别为(0, 1)、(2, 3)、...,这样,当我们知道其中的一条边i,则另一条边为i^1

  • 常用的网络流算法有:

    • (1)EK算法,时间复杂度: O ( n × m 2 ) O(n \times m ^ 2) O(n×m2);

    • (2)dinic算法,时间复杂度: O ( n 2 × m ) O(n^2 \times m) O(n2×m);

    • (3)ISAP、HLPP等。

  • 实际使用中我们并不要考虑时间复杂度,一般来说,如果点数+边数不超过一万,可以使用EK算法;如果点数+边数不超过一万,可以使用dinic算法。

2. AcWing上的网络流题目

AcWing 2171. EK求最大流

问题描述

在这里插入图片描述

分析

  • 最大流模板题。

  • 每次使用bfs算法求解残留网络中的增广路即可。

代码

  • C++
#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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有