网络流理论基础

最大流

基础知识

下面一切基础知识都是为求出最大流而服务的。

以 定义( \(\text D\) )和 引理、定理、结论、推论( \(\text T\) )的形式呈现。

  1. \(\text D\) )网络 Network :网络是一个有向图 \(G=(V,E)\) ,对于每一条边,有一个容量 capacity \(c(u,v)\) 。同时在图中还有两个特殊点 \(s,t\) ,一个叫源点一个叫汇点。

    注意在网络中我们不考虑负容量,我们总认为 \(c(u,v)\ge 0\)

    注意在网络中我们不考虑反向边,如果有反向边我们也可以拆开,就没有反向边了:

    rev.png

  2. \(\text D\) )可行流 Flow :一个流给每一条边提供了一个函数值 \(f(u,v)\) ,当满足如下条件时,它是可行流:

    性质一:容量限制 \(\forall (u,v)\in E,0\le f(u,v)\le c(u,v)\)

    性质二:流量守恒 \(\forall v\in V-\{s,t\},\sum_{(u,v)\in E}f(u,v)=\sum_{(v,w)\in E}f(v,w)\)

    网络可以想象为一个排水系统(此处应有 [NOIP2020] ),其中 \(s\) 为一个大水库, \(t\) 就是一个大池塘,我们可以通过带有每秒流量上限的管道将水从 \(s\) 运输到 \(t\) 。一个流的两个限制等价于水管不能爆,且中间的节点不能存水。

    我们可以接着定义可行流的流量 \(|f|\)\(s\) 流出的净流,也即:

    \[|f|=\sum_{(s,u)\in E}f(s,u)-\sum_{(v,s)\in E}f(v,s) \]

    此时我们就知道了最大流为网络上的最大可行流

  3. \(\text D\) )残留网络 Residual Network :这是对于原图 \(G\)\(G\) 上的任意可行流 \(f\) 定义的。我们定义 \(G_f=(V_f,E_f)\) 为:

    • \(V_f=V\)
    • \(E_f=\{(u,v)|(u,v)\in E\lor (v,u)\in E\}\)
    • \(c_f(u,v)=\begin{cases}c(u,v)-f(u,v)&(u,v)\in E\\f(v,u)&(v,u)\in E\end{cases}\)

    可以发现,我们在残留网络中引入了反向边,但是仍然强调原图中是没有反向边的

    当然,可以发现残留网络也是一个网络,所以说上面也有可行流。于是就有了下面的定义及性质:

  4. \(\text D\) )流的加法:对于 \(G\) 上的可行流 \(f\)\(G_f\) 上的可行流 \(f'\) ,我们定义 \(g=f+f'\) 在原图上的流为

    \[g(u,v)=f(u,v)+f'(u,v)-f'(v,u) \]

    此时反向边可以理解为 " 退流 " 。虽然直观上很好理解,但我们仍有必要证明一下 \(g\) 也是可行流:

  5. \(\text T\) )对于 \(G\) 上的可行流 \(f\)\(G_f\) 上的可行流 \(f'\)\(g=f+f'\) 是原图的可行流:

    性质一

    根据可行流的定义,对于原图上任意的 \((u,v)\in E\),有:

    \[\begin{cases} 0\le f'(u,v)\le c(u,v)-f(u,v)\\0\le f'(v,u)\le f(u,v) \end{cases} \]

    根据第二条有 \(f(u,v)-f'(v,u)\ge 0\) ,再根据 \(f'(u,v)\ge 0\) 可以推出 \(g(u,v)\ge 0\)

    根据第一条有 \(f(u,v)+f'(u,v)\le c(u,v)\) ,再根据 \(f'(v,u)\ge 0\) 可以推出 \(g(u,v)\le c(u,v)\)

    可知流 \(g\) 满足性质一。

    性质二

    对于 \(f'\) 有:

    \[\forall u\in V,\sum_{(v,u)\in E}f'(v,u)+\sum_{(u,w)\in E}f'(w,u)=\sum_{(u,w)\in E}f'(u,w)+\sum_{(v,u)\in E}f'(u,v) \]

    移项之后有:

    \[\forall u\in V,\sum_{(v,u)\in E}f'(v,u)-f'(u,v)=\sum_{(u,w)\in E}f'(u,w)-f'(w,u) \]

    然后加到 \(f\) 上面就能发现 \(g\) 也是守恒的。

    综上可知 \(g\) 是可行流。

    这个性质告诉我们,如果 \(G_f\) 上面有 \(|f'|>0\) 的可行流 \(f'\),那么 \(f\) 一定不是 \(G\) 的最大流

  6. \(\text D\) )增广路 Augmenting Path :

    对于任意网络上的一条从 \(s\)\(t\) 的路径 \(P\) ,定义它的容量 \(\delta(P)=\min\{c(u,v)|(u,v)\in P\}\)

    增广路 \(A\) 要求 \(A\) 是一条 \(s\)\(t\) 的路径 \(P\)\(\delta(P)>0\)

    本质上增广路就是一种最简单的可行流。结合性质 5 可以发现,最大流 \(f\)\(G_f\) 上也不会有增广路

    此时困扰我们的问题就是:对于 \(G\) 上的可行流 \(f\) ,如果 \(G_f\) 上不存在增广路, \(f\) 是否是最大流?我们还无法断言,因为有可能我们会陷入局部最优解。为了解决这个问题,我们将要引入割这个概念。

  7. \(\text D\)鸽咕咕咕 割 Cut :网络上的一个割定义为对于点集 \(V\) 的一个划分 \([S,T]\) 。它们需要满足:

    性质一: \(S\cup T=V,S\cap T=\varnothing\)

    性质二:\(s\in S,t\in T\)

    注意 \(S\)\(T\) 并不需要各自内部联通。因此一个网络的割的划分数为 \(2^{n-2}\)

  8. \(\text D\) )割的容量:定义 \(G\) 的一个割 \([S,T]\) 的容量为:

    \[c(S,T)=\sum_{u\in S}\sum_{v\in T}[(u,v)\in E]c(u,v) \]

    为了方便,我们也可以认为 \((u,v)\not \in E\Rightarrow c(u,v)=0\) 。因此上式可以简化。

    此时我们知道了最小割为网络上的最小容量割

  9. \(\text D\) )割的流量:定义 \(G\) 的一个割 \([S,T]\) 对于 \(G\)任意一个可行流 \(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) \]

    注意这里的定义是不对称的。割的容量只考虑正向边,而割的流量同时考虑正向和反向边

    显然有 \(f(S,T)\le c(S,T)\)

    仔细思考我们不难提出如下猜想:是否有 \(|f|=f(S,T)\)

    感性理解是很自然的,对于任意一个割,我们将 \(S\) 分为与 \(s\) 相通的 \(S_c\) 和不相通的 \(S_c'\) 。那么 \(S_c'\) 的部分流量守恒,而 \(S\) 流到 \(T\) 流必然会经过 \(S_c\)\(T\) 的边。下面我们将一步步证明这一点。

  10. \(\text D\) )任意点集的流量:定义 \(G\) 上的任意两个点集 \(X,Y\) 对于任意一个可行流 \(f\) 的流量为:

    \[f(X,Y)=\sum_{u\in X}\sum_{v\in Y}f(u,v)-\sum_{u\in X}\sum_{v\in Y}f(v,u) \]

    这个定义存在如下性质:

  11. \(\text T\) )对于 \(G\) 上的任意两个点集 \(X,Y\) 和任意一个可行流 \(f\)\(f(X,Y)\) 存在如下性质:

    性质一

    \[f(X,X)=0 \]

    证明略。

    性质二

    \[f(X,Y)=-f(Y,X) \]

    证明略。

    性质三

    \(Y\cap Z=\varnothing\) 时,存在:

    \[f(X,Y\cap Z)=f(X,Y)+f(X,Z) \]

    这是因为 \(X\) 流向 \(Y\) 的流量和 \(X\) 流向 \(Z\) 的流量一定不会有重复计算。

  12. \(\text T\) )割的流量与流的流量:对于 \(G\) 上的任意一个割 \([S,T]\) 和任意一个可行流 \(f\) ,存在性质:\(|f|=f(S,T)\)

    证明:

    首先有 \(|f|=f(\{s\},V)\)

    \(f(S,V)=f(\{s\},V)+f(S-\{s\},V)\)

    注意到 \(S-\{s\}\) 里面的点都满足流量守恒,因此有 \(f(S-\{s\},V)=0\)

    于是 \(|f|=f(S,V)\)

    又有 \(f(S,V)=f(S,S\cup T)=f(S,S)+f(S,T)=f(S,T)\)

    因此 \(|f|=f(S,T)\)

    可以发现我们的猜想中已经把证明口胡过一遍了

    结合定义 9 中提到的,有 \(|f|\le c(S,T)\) 。下面我们将要证明最大流最小割定理!

  13. \(\text T\)最大流最小割定理 Maximum-flow-minimum-cut Theorem :对于网络 \(G\)\(G\) 上的一个可行流 \(f\),以下三个命题是等价的:

    \((1)\) \(f\) 是最大流

    \((2)\) \(G_f\) 上不存在的增广路

    \((3)\) \(\exists [S,T],|f|=c(S,T)\)

    证明:

    首先思考一下我们证明的方式,我们可以证明 \((1)\Rightarrow (2),(2)\Rightarrow (3),(3)\Rightarrow (1)\) ,这样便可以说明三个命题是等价的。

    证明 \((1)\Rightarrow (2)\)

    请回头查看定义 6 。

    证明 \((2)\Rightarrow (3)\)

    此时我们进行构造证明:

    构造 \(S\) 为在 \(G_f\) 上从 \(\{s\}\) 出发,仅经过容量为正的边能到达的点的集合,那么 \(T\) 即为 \(V-S\)

    由于 \(G_f\) 上没有增广路,所以 \(t\not\in S\) ,所以 \([S,T]\) 构成了 \(G\) 的一个割。

    我们只需要证明 \(|f|=c(S,T)\)

    根据结论 12 中提到的,有 \(|f|=f(S,T)\) ,所以我们只需要证明 \(f(S,T)=c(S,T)\)

    根据 \(f(S,T)\) 的定义,这也就是证明 \(\forall u\in S,v\in T,f(u,v)=c(u,v);\forall v\in T,u\in S,f(v,u)=0\)

    首先考虑第一个部分,即 \(f(u,v)=c(u,v)\)

    利用反证法,如果 \(f(u,v)<c(u,v)\) ,那么 \(c(u,v)-f(u,v)>0\) ,在 \(G_f\)\((u,v)\) 的容量为正,那么 \(v\) 应该属于 \(S\) ,矛盾。所以 \(f(u,v)=c(u,v)\)

    类似的,如果 \(f(v,u)>0\) ,那么在 \(G_f\) 上,就会有 \((u,v)\) 的容量为正,那么 \(v\) 应该属于 \(S\) ,矛盾。所以 \(f(v,u)=0\)

    因此我们就证明了 \((2)\Rightarrow (3)\)

    证明 \((3)\Rightarrow (1)\)

    我们使用夹逼法。别想歪了

    根据结论 12 我们可以知道 \(|f|\le c(S,T)\) ,即:

    \[\begin{aligned} &\max_f\{|f|\}\le c(S,T)=|f|\\ \Rightarrow &\max_f\{|f|\}\le |f| \end{aligned} \]

    而又有 \(|f|\le \max_{f}\{|f|\}\) ,所以 \(\max_{f}\{|f|\}=|f|\) 。即 \(f\) 是最大流。

    证毕!

  14. \(\text T\) )这是根据最大流最小割定理的得到的推论,但是是其最常用的形式。即对于任意网络 \(G\) 有:

    \[\max_f\{|f|\}=\min_{[S,T]}\{c(S,T)\} \]

    证明:

    结合最大流最小割定理,我们知道对于最大流 \(f\)\(\exists [S,T],|f|=c(S,T)\)

    我们只需要说明 \([S,T]\) 是最小割。

    类似地,有 \(|f|=c(S,T)\le \min_{[S,T]}\{c(S,T)\}\)\(\min_{[S,T]}\{c(S,T)\}\le c(S,T)\) ,所以 \([S,T]\) 是最小割。

至此我们关于最大流的理论知识也就差不多结束了。

求解最大流

求解网络最大流有两种方法:增广法和预流推进法。

增广法

又被称为 FF, Ford-Fulkerson 方法,直接基于最大流最小割定理——也就是反复迭代直到在残留网络中找不到增广路为止。

以下算法都基于这个思想。笔者将它们按照时间复杂度上界来排序。

Ford-Fulkerson 算法

该算法每次寻找一条增广路并沿着增广路推流,维护过程结束后的残留网络

如果每次使用 DFS 搜索,时间复杂度是 \(O(|E|F)\) 的,其中 \(F\) 为图的最大流的流量。

不过据说该算法还有改进版,叫做 Scaling Max-flow Algorithm ,还有一篇国内搜出来短得离谱论文确实没看懂是什么意思

Scaling Max-flow Algorithm 在这篇博客里有提到。

Edmonds-Karp 算法

该算法思想同上,唯一的区别是确定了搜索增广路的顺序:它每次搜索最短的增广路,可以采用 BFS 实现。

经过这样的改变,时间复杂度下降到了 \(O(|V||E|^2)\) 。关于其复杂度的证明可以参考这篇博客

Dinic 算法

该算法对 EK 进行了改进,每次对最短的增广路进行多路增广

算法流程不难理解。每次迭代过程中,为了走到最短的增广路,算法会首先从 \(s\) 出发进行一次 BFS 对图进行分层。实际上我们得到了 \(d(u)\) ,为从 \(s\) 出发到达 \(u\) 的最少边数。

接着进行多路增广。根据最短路性质,如果 \((u,v)\in E\) ,那么 \(d(u)+1\le d(v)\) 。如果 \(d(u)+1=d(v)\) 则说明 \(u\) 在从 \(s\)\(v\) 的一条最短路上——也就是说我们从 \(u\)\(v\) 增广是合法的。

所以算法会再进行一次 DFS ,根据 \(d\) 的信息进行搜索,途中维护路径上的边的最小容量。这样我们每搜索到 \(t\) 的一次,我们就得到了一条增广路。回溯过程中可以顺便维护一下增广后的残留网络。

Dinic 的时间复杂度是 \(O(|V|^2|E|)\) 的,来源于每次 DFS 增广的 \(O(|V||E|)\)\(O(|V|)\) 的层数上界。

Dinic 还有一个重要的优化:当前弧优化。

当前弧优化即指,如果一条边已经满流,那么之后就没有必要再搜索它了。优化点在于,由于每个点可能会被增广很多次,所以每次遍历的边的数量会减少。

ISAP 算法

改进版最短增广路算法 Improved Shortest Augmenting Path 。大概是说在 DFS 的过程中直接维护 Dinic 的 \(d\) 这个分层标号,而不是每次再用 BFS 进行分层。优化空间貌似很大。实际上还不会。

预流推进法

考虑一个相当直接的方法:我们可以首先给 \(s\) 一个无穷大的流量,然后尝试通过边把 \(s\) 的流量给推出去,直到我们将流推到了 \(t\) 。最后当我们没法推流的时候,我们就找到了最大流。

HLPP 算法

最高标号预流推进法 Highest Label Pre-flow Push 。还不会。

求解最小割

根据最大流最小割定理,我们可以建完图之后直接跑最大流算法得到最小割。

根据最大流最小割定理的证明过程,我们也很容易构造出一个合法的最小割(如果此时你还不会,请回到定理 \(13\) 的证明)。

需要注意的是,由于网络中的流量总是非负,建图的时候一定一定注意不要建立负容量的边!如果出现了这种情况,那么一定要仔细检查自己的思路是否正确。

费用流

基础知识

费用流问题的背景是一个网络 \(G=(V,E)\) ,对于每条边 \((u,v)\) 除了容量外,还有额外的费用 \(w(u,v)\)

对于可行流 \(f\) ,我们定义它的费用:

\[w(f)=\sum_{(u,v)\in E}f(u,v)\times w(u,v) \]

对于可行流 \(f\) ,我们定义它的残余网络 \(G_f=(V_f,E_f)\) ,其中:

  • \(V_f=V\) ;

  • \(\forall (u,v)\in E_f,(u,v)\in E\lor (v,u)\in E\)

  • 容量和权:

    \[\begin{aligned} c(u,v)&= \begin{cases} c(u,v)-f(u,v)&(u,v)\in E\\ f(v,u)& (v,u)\in E\\ \end{cases} \\ w(u,v)&= \begin{cases} w(u,v)&(u,v)\in E\\ -w(v,u)& (v,u)\in E\\ \end{cases} \\ \end{aligned} \]

通常我们解决的是最小费用最大可行流问题,该问题便是求\(|f|\) 最大时, \(w(f)\) 的最小值

求解费用流

SSP 方法

SSP 方法全称为 Successive Shortest Path 方法,即 " 连续最短路 " 方法。

顾名思义,我们每次从 \(s\) 出发,以 \(w\) 作为边权搜索一条到达 \(t\) 的最短路,并沿着最短路增广。当我们无法增广的时候算法结束。

看起来非常正确,以下给出正确性证明。

证明

最大流部分:

显然,如果不存在最短增广路即等价于 \(s\) 无法到达 \(t\) ,根据最大流部分的知识,即不存在增广路,那么最终得到的一定是最大流。

最小费用部分:

  • 引理:

    定义 \(F_i\) 为所有流量为 \(i\) 的可行流的集合。则 \(w(f)=\min_{f'\in F_{|f|}}\{w(f')\}\) \(\Leftarrow\) \(G_f\) 中没有负圈。

    为了方便,以下简称左半陈述为 " \(f\) 是最小费用流 " 。

    证明

    假设 \(G_f\) 不存在负圈,但是 \(f\) 却不是最小费用流。

    找出费用更小的一个流 \(f'\) ,比较这两个流。

    由于 \(|f|=|f'|\) ,并且对于 \(u\in V-\{s,t\}\)\(u\) 在两个流中都满足流量守恒,所以 \(f\)\(f'\) 的差异必然形成了多个内部流量抵消的圈。由于 \(w(f')<w(f)\) ,所以这些圈内必然有一个总费用为负,即存在负权圈。

    对于差异中的任何一条边 \((u,v)\) ,我们可以说明它必然存在于 \(G_f\) 上:

    • 如果 \(f(u,v)>f'(u,v)\) ,则可以看作是退流。由于 \(f(u,v)>f'(u,v)\ge 0\) ,所以 \((v,u)\in E_f\)
    • 如果 \(f(u,v)<f'(u,v)\) ,则可以看作是推流。由于 \(f(u,v)<f'(u,v)\le c(u,v)\) ,所以 \((u,v)\in E_f\)

    所以 \(G_f\) 上必定存在负圈,矛盾。因此成立。

  • 正确性证明:

    对于构造过程中的任何一个流 \(f\) ,我们证明它一定是最小费用流。

    一开始,流量为 0 ,并且 \(w\) 均为正,因此 \(G_f\) 中没有负圈。

    中途过程进行反证法,假设 \(G_f\) 存在负圈,考虑两种情况:

    • \(G_f\) 里面的负圈新出现于上一步增广。由于圈上总和为负,因此增广路上总和为正,显然我们可以不走这个圈得到一条更短的路径,矛盾;
    • \(G_f\) 里面的负圈在上一步的残余网络里面。由于初始没有负圈,因此负圈一定由增广得到,矛盾;

    因此 \(G_f\) 里面不可能存在负圈,也即 \(f\) 是最小费用流。

类 Edmonds-Karp 算法

类似于 Edmonds-Karp ,每次不使用 BFS 而是最短路算法寻找增广路。时间复杂度为 \(O(|V||E|F)\) ,其中 \(F\) 为最大流的流量。

类 Dinic 算法

类似于 Dinic ,每次不使用 BFS 而是最短路算法进行分层。在搜索过程中也依靠边权确定是否合法跨层。

中途需要注意标记节点是否已经经过,避免因为 \(w=0\) 的边而搜出环。

时间复杂度退化为 \(O(|V||E|F)\)\(F\) 意义同上。原因是分层现在没有层数上限了。

类 ISAP 算法

不清楚,这是我刚刚编出来的

zkw 算法

这是由 zkw 发明的费用流算法,先引用一段有趣的故事:

最小费用流在 OI 竞赛中应当算是比较偏门的内容, 但是 NOI2008 中 employee 的突然出现确实让许多人包括 zkw 自己措手不及. 可怜的 zkw 当时想出了最小费用流模型, 可是他从来没有实现过, 所以不敢写, 此题 0 分. zkw 现在对费用流的心得是: 虽然理论上难, 但是写一个能 AC 题的费用流还算简单. 先贴一个我写的 costflow 程序: 只有不到 70 行, 费用流比最大流还好写~。

没有代码,这篇博客里不放代码。

大概过程:增广部分类似于 Dinic/ISAP ,而标号部分类似于 KM 。

具体过程:还没学会

番外:最短路算法

通常,我们处理负权最短路的时候,使用的都是 Bellman-Ford 或者 SPFA 。

但是如果你愿意,可以采用类似于 Johnson 算法的科技,给每个点加权从而消除负权边。这样你就可以使用 Dijkstra 了。

番外:负权边

注意到证明过程中我们只限制了 \(G\) 上面没有负圈,因此,当我们使用基于最短路算法的费用流算法的时候,我们可以接受负权边,只需要初始的图上不存在负圈。

但是在使用 zkw 算法的时候,图上绝对不能出现负权边,可能是因为 KM 标号过程中的限制,处理负权边的方法可以参考使用 Dijkstra 的方法。

虽然有负圈我们不能单纯地 SSP 迭代出答案,但是这并不意味着这种情况下没有最小费用最大流,只不过这个过程中我们需要做一些改变,具体操作请参考其它博客。

posted @ 2020-12-12 12:05  crashed  阅读(263)  评论(0编辑  收藏  举报