网络单纯形 学习笔记
upd: 修了英文与标点间多空格的锅。
upd: 修了中文与符号间少空格的锅,补上一处句号。
网络单纯形是一种神奇的算法。它可以求解带负圈的费用流,可以过 HLPP 板子,但它的(最坏)复杂度好像是指数级,尽管我并不会证。
感性理解:它和线规算法 simplex 有许多相似之处,而 simplex(最坏)是指数级的。
虽然但是,据 CF(见本文末尾)上所讲,它的平均时间复杂度是 \(O(VE)\),且常数较小(无 LCT 情况下)。SPFA被卡前:这我熟。
网络单纯形算法可用来求解无源汇有负圈上下界最小费用可行流。好像常见的网络流都可以转化为这个,但加入上下界后常数会略大,不知道是不是我写炸了,欢迎大佬修改。
将有源汇最小费用最大流转换为无源汇最小费用可行流的方法:从汇向源连一条费用为 \(-\infty\),流量为 \(+\infty\) 的边。实际可取 inf
为其余边费用/流量之和加一。
将上下界最小费用可行流转换为一般的最小费用可行流的方法:先所有边强制推下界的流,记录“溢出”的流,建虚拟点 \(K\),\(K\) 向所有“上溢”(流量有多余)的点连边,权为 \(-\infty\);所有“下溢”的点向 \(K\) 连边,权为 \(0\)。最后检查这些边是否跑满即可。
感性理解:若存在一条路径,从某个“上溢”的点 \(A\) 到另一个“下溢”的点 \(B\),则它与 \(B \rightarrow K \rightarrow A\) 的路径构成负环,可推流(见下文),这相当于之前我们强制推的流从这条路径回去。
网络单纯形算法的大致思路:求解最小费用可行流时,给定图 \(G=(V,E)\),在算法过程中,我们维护它的生成森林(原图可能不联通)边集 \(T\),每次找一条不在 \(T\) 内的边 \(t \in E \setminus T\),若 \(T \cup \{t\}\) 包含负环,则在 \(T\) 中沿此负环推流,选出一条满流的边删去,将 \(t\) 加入 \(T\)。重复此过程直到 \(T\) 中不含负环,我们就得到了 \(G\) 的最小费用可行流。这样的思想使得网络单纯型算法天生就支持带负环的费用流。
线规角度的解释:生成森林相当于初始可行解,向负环推流相当于转动变量。
判断一条边加入生成树后是否有负环
考虑函数 \(h:V \rightarrow \mathbf{R}\),满足对 \(\forall e \in T, h(e.\text{to}) - h(e.\text{from}) = e.\text{cost}\),那么对于两个点 \(a,b\),\(h(a)-h(b)\) 就是 \(T\) 上 \(a\) 到 \(b\) 一条路的权值之和。对边 \(e \in E\),若 \(h(e.\text{to}) - h(e.\text{from}) + e.\text{cost} < 0\),则它所在的环路(沿着它的方向)为负环。这样可做到 \(\Theta(1)\) 判断是否这条边加入后存在负环。
找到负环后推流
先从 \(e.\text{from}\) 和 \(e.\text{to}\) 向上跳到 LCA,再从两边分别找能推的最小流值,最后推流。
这里如果用 LCT 维护,则可从 \(O(n)\) 优化到 \(O(\log n)\),但常数大。
推流后,别忘了删边并反转被删的链的父子关系,保证生成树还是树。
Code
实现注意点
-
使用时间戳标记
pi
是否过期 -
建初始生成树时 一定 要从汇点(有源汇)/虚拟 \(K\) 点(上下界)开始,否则会在某些数据上 TLE,原因未知
也可以理解为玄学
一些乱搞优化
- 扫描边时预先打乱,example