网络流

定义:

对于一张存在源汇点和流量的有向图,定义为网络 \(G(E,V)\)。
对于每一条边存在一个容量大小 \(c(u,v)\),表示流量的上限,有一个流量 \(f(u,v)\) 表示一条边的流量。

\(f(x)\) 表示对于点 \(x\) 的净流量,也为 \(\sum_{v \in V}f_{x,v} - f_{v,x}\)

定义 \(|f|\) 表示图 \(G\) 的流的大小,大小为 \(f(s)\)。

一组割 \(S-T\) 表示将网络分成两个集合 \(S,T\),使得 \(S \cup T = V\), \(S \cap T = \emptyset\),且 \(s \in S,t \in T\)。

令 \(c_f(u,v) = c(u,v) - f(u,v)\),设残量网络 \(G_f = G(E_f,V)\),其中 \(E_f = \{(u,v)\mid c_f(u,v) \gt 0\}\)。

对于一组可行的流函数 \(f\) 需要满足的性质:

  • 容量限制: \(f(u,v) \leq c(u,v)\)。
  • 斜对称性: \(f(u,v) = -f(v,u)\)。
  • 流量守恒: 除了源点和汇点之外的 \(x\)满足 \(f(x) = 0\)。

最大流:

FF增广:

每次选择一条 \(s-t\) 路径,将路径上每一条边都加上等量的流量,这就是增广,最大流就是每次增广得到的流量的叠加。

此外需要对于每一条边新增一条反向边 \((v,u)\),对于这条边满足 \(f(v,u) = -f(u,v)\),这条边是给我们用来反悔的,不然增广可能导致决策错误而无法得到最大流。

这里 \(f \lt 0\) 可能十分反常,无法理解其到底指什么,实际上我们不关心一条边实际流量是多少,我们想要的只是剩余流量还有多少,初始时一条反向边的流量上限是 \(0\),我们只是希望将反向边的剩余流量增多到正向边的已用流量来达到反悔的目的。

有了反悔边之后每次直接增广就是对的了。

首先每次如果增广那么必然会使流量至少加 \(1\),所以最后肯定会得到一个解。

其次考虑增加反悔边的正确性,我们这里考虑一个路径,设有一些点 \(s,t,a,b\)。

并且有这些边 \(s \to a,s \to b,a\to b,a\to t,b\to t\),且容量都为 \(1\)。

此时考虑首先走了一条增广路 \(s \to a \to b \to t\)。

之后我们想要修改它,因为这并不优,之后在操作上我们会选择 \(s \to b \to a \to t\) 这一条路径,增加 \(1\) 的流量,这样就是对的了。

想一下为什么,我们做之后得到的所有 \(f(u,v)\) 与先操作 \(s \to a \to t\) 再操作 \(s\to b \to t\) 的是相同的。

证明:

我们用调整法,对于每一条增广路上的反悔边 \((v,u)\) 进行考虑,设其剩余流量为 \(c\),发现这里的反悔边一定是存在若干增广路经过 \((u,v)\) 使用了 \(c\) 的流量。若我们在这一次增广中使用了 \(v\) 的流量,那么此时我们相当于把之前增广中经过 \((u,v)\) 这条边的增广路中反悔 \(v\) 的流量不经过这条边,并用当前增广的路径中的前面的路径经过这条边,之后再往后走时则用的是我们反悔掉的 \(v\) 的流量往前走。

这样调整后发现与之前的方案是相同的。

此时我们可以断言若不存在增广路则可以说明当前已经得到最大流。

思考一下,此时相当于是已经形成了一组 \(S-T\) 割,因为不存在一组增广路那必然可以分成两个集合,否则可以继续增广。

由最大流最小割定理我们可以得到正确性,这个定理指出一个网络的最大流等于最小割,满足条件时当且仅当 \(S \to T\) 的边都满流, \(T \to S\) 的边都空流。

EK算法

有上面的做法,直接一点的我们就可以得到一个做法,即每次找出残量网络上的一条路径对其进行增广,每次增广的增加流量为这条路径的最小残余流量,但这个东西复杂度是不对的。

我们考虑换一种办法,每次找残量网络上一条 \(s \to t\) 的最短路径对其进行增广,这个复杂度是 \(O( V E^2)\)。

增广一次复杂度显然是 \(O(E)\) 的。

核心的复杂度保证是每次增广最短路径,可以保证增广后的残量网络中每个点到源点的距离是不降的,且只会增广 \(O(EV)\) 次。

对于一次增广,我们把残余流量最小的称作饱和边,那么对于这条边 \((u,v)\) 被作为饱和边增广的方式是交替的,即先经过正向边再反向边交替着。

令 \(d1(x)\) 为第一次这条边被作为饱和边时与源点的距离, \(d2(x)\) 为第二次与源点的距离,那么此时对于这条边有 \(d1(v)=d1(u)+1\) 且 \(d2(u)=d2(v)+1\),且由于增广后的残量网络中每个点到源点的距离是不降的,所以 \(d2(v) \geq d1(v),d2(u) \geq d1(u)\),结合一下可以发现有 \(d2(u)\geq d1(u) +2\),且显然有 \(d(x) \leq V\),于是我们可以说明一条边最多被作为饱和边 \(O(V)\) 次,那也就可以说明增广次数为 \(O(EV)\)。

于是复杂度可以分析到 \(O(|V| |E|^2)\)。

Dinic 算法

与上面的方法不同,这个算法给出一个更高妙的做法,先给出算法流程。

  • 将当前的残量网络按与源点距离分层,并规定一次增广的路径中经过的边 \((u,v)\) 满足 \(d_v = d_u +1\)。

这里给出一个定义,令这次找出的层次图为 \(G_L=\{(u,v) \mid d_v = d_u+1\}\),定义阻塞流表示在 \(G_L\) 中得到的极大的增广路,即无法扩展的。

  • 增广时考虑不写成多次增广,每次增广一路的形式,写成多路增广的形式,每次对于每个点 \(u\) 记下一个时间戳 \(cur_u\),表示 \(u\) 的前 \(cur_u - 1\) 条边已经被增广使得残余流量为 \(0\),因为你严格规定了只能有 \(d_v = d_u +1\) 的边流,对于 \((v,u)\) 这条边新的流量是不会用到的。我们用 \(dfs\) 的形式来写。

首先考虑证明一下单次求阻塞流的复杂度:

对于分层之后的路径,由于层数最多为 \(V\),所以一条路径最多跳转 \(V\) 个点,且每一次都会使得一个饱和边的残余流量变为 \(0\),若一次增广成功,即至少有将一个存在残余流量的边的残余流量变为 \(0\),则每次代价为 \(V\),但是由于你是在 dfs,那么你可能最后一条边走到某个点后无法增广,那么这种边是没用了的,我们用当前弧优化保证下次不会再遍历到这个点,那么这里同样是 \(O(V)\)。

综上,两种情况讨论后我们可以得到一次求阻塞流复杂度为 \(O(EV)\)。

可以证明每次增广时层次图的层数单调递增,这个我不会证。

最小割

对于割 \(S-T\),其容量为 \(\sum_{u \in S} \sum_{v\in T} c(u,v)\)。

由最大流最小割定理,跑一遍上面算法即可。

求一组最小割的方案即为在残量网络上,每次只走剩余容量 \(\gt 0\) 的边,归入 \(S\) 集合即可。

判定一组解是否合法只需要看它在残量网络上 \(S \to T\) 的所有边集是否全部为 \(0\),与边权无关。

边为割边的可行和必经:

首先考虑对残量网络上边还有残留容量的边缩点,之后再把残留容量为 \(0\) 的边加入,将缩后的点连接,那么可以变为一个 \(DAG\),对于割边集可以直接划分为左右两个联通块取中间 \(S\to T\) 的边肯定不劣。

  • 可行边:首先肯定在残量网络上流量为 \(0\),其次在残量网络上不存在一个 \(u \to v\) 的不经过边权为 \(0\) 的边的路径,否则可以退一点流,然后让这个路径流。这样就可能出现另一组最大流这条边残量网络上不为 \(0\) 的情况,也就是两个点要在同一强连通分量中。
  • 必经边:首先要是可行边子集,其次需要满足的是 \(u\) 和 \(S\) 在同一强连通分量, \(v\) 和 \(T\) 在同一强联通分量。

选/不选问题

当一个问题中出现选或不选对于某个人带来一些代价时,考虑将选择与不选分别建立 \(S,T\),之间如果有连锁的一些代价就只用在中间的点建模,对于割掉一个看作决策中不选择这个,例如如果 \(i\) 选择,就割掉 \(i \to T\) 的边,对于选择来说这样肯定就对了,但对于连锁带来的贡献来说,一般会因为你断掉一些边而迫使这条边必须断掉,从而达到我们的要求,具体问题具体分析。

1.对于一个网络,求出一组割边数量最小的割:

把所有流量设为 \(1\),跑一边最大流即可。

2.对于一个网络,求出一组割边数量最少的最小割:

有两种办法。

  • 将所有流量变为 \(f(u,v) (|E| +1) +1\)。

此时相当于以流量为第一关键字,割边数量为第二关键字跑最小割,最后最小割为 \(\frac{maxflow}{|E|+1}\),割边数为其余数。

  • 先跑一遍最大流,再对于这张残量网络建图,对于一个正向边若是满流的话,则建一条流量为 \(1\) 的边,否则连流量为 \(\infty\) 的边。对于反向边若是流量为 \(0\) 则不连边,否则连一条流量为 \(\infty\) 的边,之后再跑一遍最小割。

分析一下这个做法的正确性。

发现我们只需要证明任取一组最大流,最终对于每一条边得到的流量 \(f(u,v)\) 满足,对于任意一组满足其为最小割的割 \(S-T\) 中,都有当 \(u \in S,v\in T\) 时,存在 \(f(u,v) = c(u,v)\) 且 \(f(v,u) =0\)。

证明:

考虑对于任意一组最小割 \(S-T\),任取一组最大流后得到的每条边在原图的流量 \(f\)。

首先由于最大流最小割定理有 \(|f| = c(S,T)\)。

然后有 \(|f| = \sum_{u \in S} \sum_{v \in T} f(u,v)- f(v,u)\)。

其次有 \(c(S,T) = |f| = \sum_{u \in S} \sum_{v \in T} f(u,v)- f(v,u)\)。

由于 \(\sum_{u \in S} \sum_{v \in T} f(v,u) \geq 0\),所以有 \(c(S,T) \leq \sum_{u \in S} \sum_{v \in T} f(u,v)\)。

又有 \(\sum_{u \in S} \sum_{v \in T} f(u,v) \leq c(u,v) = C(S,T)\),所以 \(\sum_{u \in S} \sum_{v \in T} f(u,v) \leq C(S,T)\)。

所以有 \(C(S,T) = \sum_{u \in S} \sum_{v \in T} f(u,v)\),且 \(\sum_{u \in S} \sum_{v \in T} f(v,u) = 0\)。

于是得证。

那在这张图中的所有割的容量 \(\lt \infty\) 的割都对应原图的一组最小割,于是求出最小割即对应原图的一组割边最少的最小割。

费用流

初始无负圈时的最小费用最大流:

SSP 算法:

先给出流程:

  • 每次找到一条费用最小的增广路进行增广。
  • 重复直到没有增广路。

证明:

首先存在一个理论为:
固定流量为 \(F\) 时,\(f\) 为最优流当且仅当不存在费用负圈。

首先证明必要性:

若存在负环直接沿着负环跑一遍会得到更小费用。

再证明充分性:

考虑反证。

假设存在一个更优流 \(g\) 使得 \(cost(g) \lt cost(f)\)。

由于 \(|f| = |g|\),对于边 \((u,v)\) 来说,有一条 \(f(u,v) - g(u,v)\) 的边,若为正则是正向边,否则为反向边,所以 \(g-f\) 一定是若干个环,否则会增加流量。

由于 \(cost(g) - cost(f) = cost(g-f) \lt 0\),所以一定至少存在一个环的费用 $\lt 0 $,所以存在负环。

与题设矛盾。

那么就有当不存在费用负圈 \(f\) 为最优流。

同时我们可以保证这样做可以在流量为任意时都为最优费用,因为每次选出的最小费用不降,证明与前文 \(EK\) 复杂度证明类似。

于是有了这个算法我们就可以直接把 \(EK\) 算法中的每次找最短路换成找最小费用,但同时也无法保证复杂度了,每次找最小费用路径的复杂度为 \(O(nm)\),最多增广 \(|f|\) 次,复杂度为 \(O(nm |f|)\),实际表现优异。

初始有负圈时的最小费用最大流

下文中的上下界网络流会提到。

上下界网络流

此处每条边的流量范围为 \([l_i,r_i]\)。

无源汇可行流

考虑先将所有边的流量全部取到下界。

新建一个超级源点 \(S\) 和超级汇点 \(T\)。

注意:这两个点只有一个调节流量的作用,与这个可行流的大小没有任何关系。

接下来对于所有边的流量进行调整,若一条点 \(x\) 的 \(f(x) \gt 0\),说明这个点需要再流出 \(f(x)\) 的流量,此时 \(x \to T\) 连一条容量为 \(f(x)\) 的边,用来保证它再流出这么多的流量。若 \(f(x) \lt 0\),那么此时这个点需要再流入 \(-f(x)\) 的流量,此时 \(S \to x\) 流容量为 \(-f(x)\) 的边,用来保证最后在平衡的基础上再流入 \(-f(x)\) 的流量。

最后若这些附加边残量都为 \(0\) 则说明找到一组可行流,否则就无解。

有源汇可行流

在上面的基础上将 \(t\) 与 \(s\) 连上一条容量为 \(\infty\) 的边,将其转化为无源汇可行流。

但既然此时已经有源汇了,那么我们存在可行流的大小。

因为我们把其改造之后所有从 \(s\) 流向 \(t\) 的流会通过我们的这条附加边流回 \(s\),那么此时可行流的大小就是 \((t,s)\) 这条边反向边的流量。

有源汇最大流

有结论:
对于任意可行流,对于基于增广的最大流算法在跑完这个可行流的残量网络上跑,可以得到最大流,因为增广本来就支持反悔。

那跑完可行流后把超级源点超级汇点和新加的 \(t \to s\) 的 \(\infty\) 边删除后跑最大流即可。

有源汇最小流

你相当于想要退掉更多的流,那你直接以汇点作为起点,源点作为终点跑最大流即可,再把这些减掉就是答案。

带负圈的最小费用最大流

此时我们需要进行消圈。

考虑强制让负权边满流,然后再建一个容量为 \(c(u,v)\),流量为 \(0\) 的反边 \((v,u)\) 用来反悔。

那么由于负权边满流所以初始时残量网络中不存在负权边,之后直接跑 \(SSP\) 即可。

posted @ 2026-09-16 17:16  lmy333  阅读(9)  评论(0)    收藏  举报