有负环的费用流问题:用消消乐“白嫖”的艺术

前文回顾:https://www.cnblogs.com/ofnoname/p/18731222

想象你是一家快递公司的调度员,每天的任务是将货物从仓库高效送到客户。你设计了一条完美路线:每辆卡车都走最短路径,运费最省,按时送达------直到有一天,某个司机突然上报了一个诡异的现象:

"老板,我的卡车在某个路口绕圈转了10次,运费反而比直送更便宜!"

你眉头一皱,打开监控系统,发现某个环形路口形成了一个**"流量漩涡"**:卡车反复绕圈,既不从仓库出发,也不抵达客户,但总运费却在下降。这合理吗?

前置知识闪电回顾

在之前的冒险中,我们已经征服了两个关键算法:

  1. 最大流:用 Dinic 或 Edmonds-Karp 打通网络,让流量像冲向终点。
  2. 无负环的最小费用流 :每次沿着残留网络中的最短费用路径增广,保证每一步都最省钱。

那时的世界是简单的------最短路径增广法,坚定地朝着汇点前进,从不绕路,因为图中没有负费用边,在图里绕圈既不能增加最大流,也不能降低费用,却浪费的宝贵的边容量限制。

但当负环出现时,情况就不一样了

现实中的交通网络可能有这样的阴谋:

  • 某条环形公路的过路费为负数(比如政府补贴绕路减排)。
  • 卡车司机发现:与其直奔终点,不如在环上多绕几圈"白嫖"补贴,总运费反而更低!

在算法世界中,这就是负费用环的破坏力

  • 满足节点流量平衡和边容量限制的情况下,某一部分流量可以既不来自源点,也不流向汇点,而是在环上无限循环
  • 传统的最短路径增广法会陷入死循环(bellman-ford / spfa 不能解决负环的最短路)。

"如何在不减少总流量的前提下,通过科学'绕圈'把运费降到最低?"

这要求我们跳出原来的思维定式,负环可以是敌人,也可以是盟友。既然如此,我们可以在残留网络中精准追踪这些费用黑洞,将它们变成降低费用的优化工具。

"当流量开始打转,费用流的江湖便多了一条潜规则:真正的极简主义,不是拒绝绕路,而是消灭所有不必要的绕路。"

有负费用环的费用流问题

我们已经知道,初始没有负费用环的图,可以运行最短费用路径的增广,保证永不出现负环,但其复杂度并不稳定;如果我们使用了其他增广(如直接使用 dinic ),可以得到最大流,但其中就会出现负环,并非最小费用;而初始有负费用环的图,更需要我们直面负环。

绕圈如何"薅羊毛"?

假设存在一个负费用环 $ C $,其总费用为 $ \sum_{(u,v) \in C} c(u,v) = -10 $,环上最小残余容量为 $ \delta = 3 $。

  • 增广操作:沿环推送 $ \delta = 3 $ 的流量。
  • 费用变化:总费用减少 $ 3 \times (-10) = -30 $。
  • 流量守恒:环上的流量增减相互抵消,总送达量不变。但费用通过负环被降低。

\[\text{新费用} = \text{旧费用} + \delta \cdot \sum_{(u,v) \in C} c(u,v) \]

因为 $ \sum c(u,v) < 0 $,所以费用不升反降。我们通过在负环上绕圈降低了费用,且不影响最终流量。

消圈算法:把"黑洞"变成"提款机

我们这样来实现消圈:

  • Step 1. 暴力输出最大流:用任意最大流算法(如 Dinic)等算法快速铺开流量,首先达成最大流,但此时费用可能不是最优。
  • Step 2. 精细化消圈:在残留网络中"排雷"。在残留网络中用 Bellman-Ford / SPFA 扫描负费用环,
  • Step 3. 增广负环:选择一个负环 $ C $,通过负环增广优化费用。沿 $ C $ 推送尽可能多的流量,直到环上某条边容量耗尽。减去相应的费用。这个负环也就被消除了。

重复检测与打击,直到网络恢复无负环。

为什么这么做?

定理1 :沿负环增广不改变总流量。
证明

  • 设原流为 $ f $,沿环 $ C $ 增广 $ \delta $,得到新流 $ f' $。
  • 对任意节点 $ u \in C $,流入增量 = 流出增量(环上每边增减 $ \delta $),故流量守恒。
  • 源点 $ s $ 和汇点 $ t $ 不参与环 $ C $,因此 $ |f'| = |f| $。

直觉上看,有一部分流量既不从源点出发,也不到达汇点。而是一直在图中占据边容量转圈以减小费用。某一个节点的流出/流入量可能比源点更多!

定理2 :流差分解定理

设 $ f $ 和 $ f' $ 为两个不同的最大流。定义差流 $ \Delta = f' - f $,则 $ \Delta $ 满足:

  • 流量守恒:对任意节点 $ u $, $ \sum_{(v,u) \in E} \Delta(v,u) = \sum_{(u,v) \in E} \Delta(u,v) $;
  • 容量约束:$ |\Delta(u,v)| \leq \text{残余容量}(u,v) $。
    差流 $ \Delta $ 可分解为若干简单环的叠加,即:

\[\Delta = \sum_{C \in \mathcal{C}} \delta_C \cdot \chi_C \]

其中 $ \chi_C $ 为环 $ C $ 的指示函数,$ \delta_C $ 为沿环 $ C $ 的增广量。

这个定理符合直觉较容易理解,因为对两个最大流做差:

\[\text{Cost}(f') - \text{Cost}(f) = \sum_{(u,v) \in E} c(u,v) \cdot \Delta(u,v) = \sum_{C \in \mathcal{C}} \delta_C \cdot \sum_{(u,v) \in C} c(u,v). \]

若 $ \text{Cost}(f') < \text{Cost}(f) $,则至少存在一个环 $ C $ 满足:

\[\sum_{(u,v) \in C} c(u,v) < 0 \quad \text{(负费用环)}. \]

实际上,"不存在负费用环"和"是费用最小的最大流"是充分必要条件。所有最大流的差异均可表示为若干环的叠加。若存在费用更小的最大流,其差流中必含负费用环;反之,若残留网络无负费用环,则当前流费用最小。

所以,消圈算法只需要先找到任意一个最大流,通过消除其中的负环,逐步优化费用,最终总是可以得到最小费用最大流。

负环的高效选择策略

假设残留网络中存在多个负环,选择哪一个呢?这直接关系到算法的正确性。你的名字叫做 Bellman-Ford,是一名负环猎人,当你冲进残留网络。眼前出现了三个负环:

  • 环A:总费用-30,长度10条边(平均每条-3)。
  • 环B:总费用-8,长度2条边(平均每条-4)。
  • 环C:总费用-100,长度50条边(平均每条-2)。

问题:你会优先消灭哪个环?

  • 无脑选择:随机选择一个环,这使得复杂度和值域相关,达到指数级复杂度
  • 菜鸟选择:总费用最低的环C(-100),以为能省最多钱。
  • 高手选择:平均费用最低的环B(-4/边),这才是真正的"性价比之王"。

最小平均费用环(MMCC)消圈算法

定义

对环 $ C $,其平均费用为:

\[\mu(C) = \frac{\sum_{(u,v) \in C} c(u,v)}{|C|} \]

即费用之和除以总长度。算法每一轮会选择找到 $ \mu(C) $ 最小的负环。

操作步骤

  1. 选择消圈:和朴素的消圈一样,在残留网络中循环"排雷"并消圈,直到不存在负圈。
  2. 计算最小平均费用环:怎样找到平均费用最小的环?动态规划是方法之一。
  • 以 \(f_{k,j}\) 表示源点刚好走 \(k\) 条边到达节点 \(j\) 的费用最短路径,那么可用 \(f_{k,j} = \min_{(i,j) \in A} \left\{ f_{k-1,i} + c_{ij} \right\}\) 完整递推。
  • 接下来枚举环的起点和长度获得最小的平均费用:\(\mu^* = \min_{j \in \mathbb{N}, 0 \leq k \leq n-1} \left( \frac{f_{n,j} - f_{k,j}}{n - k} \right)\)。
  • 将原图费用边权视为都加上 \(|\mu^*|\),再运行最短路径算法,此时的零权重环就是原图的最小平均费用环。一轮的复杂度一共是 \(O(mn)\)。
  1. 数学魔法:每次消灭该环后,可以保证残留网络的最小平均费用 $ \mu_{\text{min}} $ 严格不降。

单次操作的复杂度上界是 \(O(mn)\);每次消灭操作减少的费用与 $ \mu_{\text{min}} $ 相关。可以此用数学知识证明:总迭代次数被证明为 $ O(m^2 n \log n) $。

策略 时间复杂度
随便选一个负环 $ O(m^2nCU) $ 和边权相关
最小平均费用环(MMCC) $ O(m^3 n^2 \log n) $

代码略。