网络单纯形 学习笔记

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

here

实现注意点

  1. 使用时间戳标记 pi 是否过期

  2. 建初始生成树时 一定 要从汇点(有源汇)/虚拟 \(K\) 点(上下界)开始,否则会在某些数据上 TLE,原因未知

    也可以理解为玄学

一些乱搞优化

  1. 扫描边时预先打乱,example

参考资料

  • Codeforces[1](强烈推荐看原文)
  • 冰中火大佬的 blog[2]

  1. [Tutorial] Network simplex ↩︎

  2. 感性理解网络单纯形 ↩︎

posted @ 2023-06-21 20:09  383494  阅读(131)  评论(0编辑  收藏  举报