网络流
网络流
带权有向图 \(G=(V,E)\),有两个特殊的点 \(s,t\),权 \(c(u,v)\) 称为流量上限。
定义这个图上的一个流为 \(f(u,v)\),其中满足两条限制:
-
\(\forall u\neq s,u\neq t,\sum_v f(u,v)=\sum_v f(v,u)\)。
-
\(f(u,v)\le c(u,v)\)。
定义这个流的大小 \(|f|=\sum_v f(s,v)-\sum_v f(v,s)=\sum_v f(v,t)-\sum_v f(t,v)\)。第二个等号可以通过对剩余的所有点叠加流量平衡限制来得到。
因为我们后面要引入反向边,所以我们可以假设这张图是没有“反平行边”的。具体来说,假设有反平行边,我们可以通过在其中一条边的中间插入一个点,来得到一个等价的图。
事实上,实践中我们往往没有这么做,而是直接加入重边。在后面的证明过程中,把重边直接揉到一起应该也能做。
接下来我们对这个图上的一个流 \(f\),定义剩余流量:
残量网络定义为 \(G_f=(V,E_f),E_f=\{(u,v)|c_f(u,v)>0\}\)。
这个东西事实上就是引入了反向边,我们在原图上一条边流过一个流量,在减小容量限制的同时还要给反向边增加一个容量。
有的时候,我们也会说流具有反对称性,也就是说 \(f(u,v)=-f(v,u)\),这样可以简化一些式子,但是终归有些不严谨。
定义一个割是集合的二元组 \((S,T)\),其中 \(s\in S,t\in T,S\cup T=V,S\cap T=\emptyset\)。
定义这个割的大小 \(||(S,T)||=\sum_{s\in S}\sum_{t\in T}c(s,t)\)。
横跨切割的净流量是 \(f(S,T)=\sum_{s\in S}\sum_{t\in T}f(s,t)-f(t,s)\)。
给出一个流 \(f\) 和一个割 \((S,T)\),我们有 \(|f|=f(S,T)\)。
同时,我们有 \(||S,T||\ge f(S,T)\)。
可以看到,两个等号成立的条件分别是返回来的边都要是空的,以及所有正着的边必须是满流的。
下面阐述一个重要的定理(最大流最小割定理)。
下述陈述等价:
-
\(f\) 是 \(G\) 的最大流。
-
\(G_f\) 中没有增广路。
-
\(|f|=c(S,T)\)。
\(1\rightarrow2\):假设存在增广路,那我们增广可以得到更大的一个流。
\(2\rightarrow3\):我们不妨令 \(S\) 是 \(G_f\) 中源点可以到达的点的集合,\(T=V-S\)。那你考虑一对点 \((u,v),u\in S,v\in T\),如果 \((u,v)\in E\),那么有 \(f(u,v)=c(u,v)\),否则 \(v\) 就会在 \(S\) 中。如果 \((v,u)\in E\),那么有 \(f(v,u)=0\),那也就是说我们证明了上面两个取等条件。
\(3\rightarrow1\):因为所有的割比所有的流都要大,如果一个流跟一个割相等,那这个流一定是最大的。
Dinic
这里就写一点注意事项。
使用当前弧优化的时候,不要跳过没有流满的边。实践中,不可以写成 for (int &i = cur[u];i;i = e[i].nxt),因为如果这一条边没有流满,也会被跳过,会导致 TLE。
复杂度证明分为两部分:分层次数为 \(O(n)\),单次分层后增广复杂度为 \(O(nm)\)。
我们先说后面一部分。对于每条成功的增广路而言,我们至少会把一条边的剩余流量搞到 0,并且这条增广路长度至多是 \(n\),并且由于我们分了层,所以加入的反向边不会被增广。
对于那些没有成功增广的部分,我们记最后一条边的集合是 \(E_2\),这样的边也最多有 \(m\) 条。
总之这部分是 \(O(nm)\)。
前面一部分,我不太会,有兴趣去看吧。
https://www.cnblogs.com/alex-wei/p/network_flow_bipartite_graph_and_graph_matching.html
https://oi-wiki.org/graph/flow/max-flow/
费用流
SSP 算法,有基于 EK 和 Dinic 两种写法。
听说有 “最大流不卡 Dinic,费用流不卡 EK” 的说法。
正确性证明:
对于两个流量相等的 \(f,f'\) 而言,若 \(|f|>|f'|\),那么我们知道 \(f-f'\) 至少有一个正流负环。这是充要条件。
我们考虑归纳证明。假设对于流量为 \(i\) 的流,这个算法求出了最优解 \(f\),并且残量网络上没有负环。考虑下一次它求出了 \(f'\),但最优解是 \(f''\),那我们就知道 \(f''-f'\) 上有正流负环,那就说明 \(G_f\) 中有负环,那就爆了。
所以根据归纳法,只要初始残量网络上没有负环,那么这个算法就能给出正确答案。
upd
我们来尝试找出这些最大流算法的共同点,并加以证明。
倘若在最短路分层图上,没有增广路,那么在原图上也没有增广路。
这个过于显然了。
无环的 \(s-t\) 流可以看成是一堆 \(s-t\) 的路径的和。
我们考虑对边数进行归纳。考虑找到任意一条 \(s-t\) 的路径,这样的路径一定存在。然后我们选择这路径上流量最小的点,减一下,这样至少会少一条边,并且还是一个无环的 \(s-t\) 流,我们拆出一堆路径,并上新找出来的即可。
一次增广最短路过后,残量网络上 \(s\) 到任意点的最短路不下降。
我们考虑反证法。你假设是 \(G+f=G'\),\(s\to x\) 的最短路下降了。你把这个在 \(G'\) 上的路径设出来,比方说是 \(p_1=s\to p_2\to\dots\to p_n=x\)。这中间每一条边,要么是 \(G\) 上的边,要么是 \(f\) 的反边。为了方便起见,我们这里直接把第一个 \(dis'_x<dis_x\) 的 \(x\) 当成我们的 \(x\),上一个点叫做 \(y\),满足 \(dis'_y\ge dis_y,dis'_y+1=dis'_x\)。
你考虑 \((y,x)\) 这条边,它一定不会是 \(G\) 上的边,那就只能是来自于 \(f\) 的反边,那就说明 \(dis_x+1=dis_y\),那么 \(dis'_y+1=dis'_x<dis_x=dis_y-1\),这显然矛盾。
我最开始想的也是分讨这条边是不是原图上的,但是没有想到取出第一个 \(x\) 出来。这样确实简单了很多,我们只用考虑一条边的情况。
EK 算法的增广次数是 \(O(nm)\) 的。
一次增广,至少会有一条边 \((u,v)\) 从残量网络中删除。考虑这条边下一次出现是怎么回事,一定是 \((v,u)\) 这条边被增广了。那我们有 \(dis_v=dis_u+1,dis'_u=dis'_v+1\),而 \(dis'_u\ge dis_u,dis'_v\ge dis_v\),所以 \(dis'_u=dis'_v+1\ge dis_v+1\ge dis_u+2\),那这样一条边最多会被作为关键边 \(O(n)\) 次,所以总增广次数是 \(O(nm)\)。
Dinic 算法当中,每次增广 \(s\to t\) 最短路长度增加。
我们考虑流 \(f+\Delta f=f'\),以及在 \(G_f,G_{f'}\) 上的最短路分别是 \(dis,dis'\),考虑一条在 \(G_{f'}\) 上的最短路 \(s=p_0\to p_1\to\dots\to p_k=t\),那么我们知道 \(dis'(p_i)=i\),还有 \(dis(p_k)=dis'(p_k)=k\)。
如果,\(dis(p_i)=i\) 都成立,那么这条路是 \(G_f\) 上一条增广路,直接就被干掉了。
我们找到第一个 \(i\) 使得 \(dis(p_i)<i\),又因为 \(dis(p_k)=k\),如果 \(dis(p_i)+1\ge dis(p_{i+1})\) 恒成立,那么这肯定不行。所以你能找到一个 \(p_x\),\(dis(p_x)+1<dis(p_{x+1})\),这就说明 \((p_x,p_{x+1})\) 不在 \(G_f\) 上。
那就说明 \((p_{x+1},p_x)\) 被增广了,这就说明 \(dis(p_{x+1})+1=dis(p_x)<dis(p_{x+1})-1\) 矛盾。
事实上,每次增广之后,所有与 \(s\) 连通的点,最短路长度都会增加。
对于单位网络,Dinic 的增广次数是 \(O(\sqrt{m})\) 的。
你考虑前 \(\sqrt{m}\) 之后的某一次增广,这时最短路长度一定 \(\ge \sqrt{m}\),那就说明我们对残量网络分层,一定有一层边数不到 \(\sqrt{m}\),那么我们直接把这些边割掉,这是个割,所以残量网络的最大流不超过 \(\sqrt{m}\),所以增广次数不超过 \(O(\sqrt{m})\)。
同样的,我们还可以证明增广次数是 \(O(n^{\frac 23})\) 的。
你考虑前 \(2n^{\frac 23}\) 之后某一次增广,分层后,至多有 \(n^{\frac 23}\) 个 \(>n^{\frac 13}\) 的层,所以一定会有两个 \(\le n^{\frac 13}\) 的层相邻,把这两层之间的所有边都割掉就可以了。
对于除了 \(s,t\) 以外每个点都满足 \(indeg(u)=1/outdeg(u)=1\) 的图,增广次数是 \(O(\sqrt{n})\)。
你考虑前 \(\sqrt{n}\) 次之后某一次增广,这时一定能找到一个 \(\le \sqrt{n}\) 的层,你考虑割掉所有这种 \(deg=1\) 的那条边,这是一个割。
另外,这上面的任意流总能分割成若干单位流量、点不交的增广路。
费用流每次增广过后,每个点的最短路不会增加。
这个可以考虑使用 EK 的类似的证明方法。
这个其实说明了费用关于流量是一个凸函数。
上下界网络流
无源汇可行流。
我们先强制所有边都流一个下界,然后对于每一个点,考虑它现在是需要流入还是流出。新建超级源汇,如果需要流入,那就从超级源引一条边。流出类似。然后跑最大流,看看超级源汇连的边是不是满流。
显然新图可以转化回原图,原图也可以转化过来。
有源汇可行流。
我们从源向汇、从汇向源连 \([0,INF]\) 的边转化回去。
有源汇最大流。
我们先求出一个可行流,然后在残量网络上增广。
有源汇最小流。
先求出一个可行流,然后从 \(T\to S\) 跑最大流,退流。
有源汇费用流。
这东西真能跑?
有负环的费用流。
我们先强制所有负权边流满,然后给出一个退流选项,同时类似于上下界的建图方式,我们新建源汇点,然后相应连边。然后跑上下界有源汇费用流。
至此,我们的科技算是点完了。
一些定理
Hall 定理:一张二分图的最大匹配,等于 \(n+\min(n(S)-S)\)。
这个相当于一个最小割,我们枚举左部点哪些选哪些不选,然后对应到右部点上就是 \(s(S)\)。
推论:正则二分图存在完美匹配拆分。
这个听说有一个随机化的 \(O(n(d+\log n))\) 的算法,就是匈牙利算法,每次随机选一条出边,如果成了环,那么就把整个环删掉,回到上一个节点,继续跑。
同时,如果 \(d=2^k\),我们有一个做法。跑无向图欧拉回路,然后这个时候每个点的出度入度都是 \(\frac d2\),按照边的方向,分成两张图,递归下去。这个复杂度是 \(O(ndk)\)。
事实上,遇到奇数,可以跑上面的随机化算法,让 \(d\leftarrow d-1\),然后再递归。
Dilworth 定理:DAG 最小可重链覆盖等于最长反链。
不知道这个有什么用。

浙公网安备 33010602011771号