xxx 最小费用最大流问题的 Successive Shortest Path with Potentials 算法
字数 2653 2025-11-30 02:00:43
xxx 最小费用最大流问题的 Successive Shortest Path with Potentials 算法
题目描述
最小费用最大流问题(Minimum Cost Maximum Flow, MCMF)是在一个带权有向图中,每条边有容量限制和单位流量的费用。目标是在满足容量约束的前提下,从源点 \(s\) 到汇点 \(t\) 输送尽可能多的流量,并使得总费用最小。Successive Shortest Path with Potentials 算法是解决该问题的高效方法,通过结合最短路径算法和势函数(Potentials)来消除负权边,从而避免使用效率较低的 Bellman-Ford 算法反复计算最短路径。
解题过程
-
问题建模
- 设图 \(G=(V,E)\),每条边 \(e=(u,v)\) 有容量 \(c(e) \geq 0\) 和费用 \(w(e)\)(可能为负)。
- 目标:在流量守恒约束和容量约束下,最大化从 \(s\) 到 \(t\) 的流量,最小化总费用 \(\sum_{e} f(e) \cdot w(e)\)。
-
算法核心思想
- 算法逐步增加从 \(s\) 到 \(t\) 的流量,每次沿当前残量网络中费用最小的路径(最短路径)推送流量。
- 关键挑战:残量网络中可能存在负权边(反向边费用为原边的相反数),直接使用 Dijkstra 算法需保证无非负权环。势函数通过调整边权,使所有边权非负,从而允许使用高效的 Dijkstra 算法。
-
势函数(Potentials)的作用
- 为每个节点 \(u\) 分配势 \(\phi(u)\),将边 \((u,v)\) 的权重调整为 \(w_{\phi}(u,v) = w(u,v) + \phi(u) - \phi(v)\)。
- 性质:调整后的路径长度与原路径长度仅差一个常数(\(\phi(s) - \phi(t)\)),因此最短路径不变。
- 目标:通过选择合适的 \(\phi\),使得所有残量边满足 \(w_{\phi}(u,v) \geq 0\),从而可使用 Dijkstra 算法。
-
算法步骤
初始化:- 流量 \(f(e) = 0\),总流量 \(F = 0\),总费用 \(Cost = 0\)。
- 势函数初始化为 \(\phi(u) = 0\)(或通过一次 Bellman-Ford 计算,确保初始非负权)。
主循环(直到无法从 \(s\) 到 \(t\) 推送流量):
- 步骤 1:在残量网络中使用势函数调整边权:
对残量边 \(e=(u,v)\),定义调整后权值 \(w_{\phi}(e) = w(e) + \phi(u) - \phi(v)\)。- 若 \(e\) 为原边且剩余容量 \(c_f(e) > 0\),则权值为 \(w(e)\)。
- 若 \(e\) 为反向边(对应原边流量 \(f(e) > 0\)),则权值为 \(-w(e)\)。
- 步骤 2:在调整后的残量网络上运行 Dijkstra 算法,求从 \(s\) 到所有节点的最短距离 \(d(u)\)(基于 \(w_{\phi}\))。
- 若 \(t\) 不可达,终止算法。
- 步骤 3:沿找到的最短路径 \(P\)(从 \(s\) 到 \(t\))推送流量:
- 推送量 \(\Delta = \min\{ c_f(e) \mid e \in P \}\)。
- 更新路径上每条边的流量:对前向边增加 \(\Delta\),对反向边减少 \(\Delta\)。
- 更新总流量 \(F \leftarrow F + \Delta\),总费用 \(Cost \leftarrow Cost + \Delta \cdot \sum_{e \in P} w(e)\)。
- 步骤 4:更新势函数:\(\phi(u) \leftarrow \phi(u) + d(u)\)。
- 此操作保证下一轮调整后的边权仍非负(关键性质:\(d(v) \leq d(u) + w_{\phi}(u,v)\) 在最短路径树中成立)。
-
正确性说明
- 势函数更新后,对于残量边 \((u,v)\),新权值满足:
\[ w_{\text{new}}(u,v) = w(u,v) + \phi_{\text{new}}(u) - \phi_{\text{new}}(v) = w(u,v) + [\phi(u) + d(u)] - [\phi(v) + d(v)] = [w_{\phi}(u,v)] + [d(u) - d(v)] \geq 0 \]
因为 $d(v) \leq d(u) + w_{\phi}(u,v)$,即 $w_{\phi}(u,v) + d(u) - d(v) \geq 0$。
- 因此算法始终在非负权图中运行 Dijkstra,保证高效性。
- 复杂度分析
- 若使用二叉堆实现 Dijkstra,每次找最短路径的时间为 \(O(m \log n)\)。
- 最多推送 \(F_{\max}\)(最大流值)次流量,总复杂度为 \(O(F_{\max} \cdot m \log n)\)。
- 通过势函数避免重复运行 Bellman-Ford,显著优于基础 Successive Shortest Path 算法(后者复杂度为 \(O(F_{\max} \cdot m \cdot n)\))。
实例演示
考虑一个简单网络:
- 节点 \(V=\{s,a,t\}\),边:
\((s,a)\):容量=2,费用=1;
\((a,t)\):容量=2,费用=2;
\((s,t)\):容量=1,费用=4。 - 目标:从 \(s\) 到 \(t\) 的最小费用最大流。
执行过程:
- 初始势 \(\phi=0\),残量网络边权与原图相同。
- 第一轮 Dijkstra 找到最短路径 \(s \to a \to t\)(费用和=3),推送流量 \(\Delta=2\),更新费用 \(Cost=6\),更新势 \(\phi(s)=0, \phi(a)=1, \phi(t)=3\)。
- 第二轮:残量网络中边 \((s,t)\) 权值调整为 \(4 + 0 - 3 = 1\),路径 \(s \to t\) 被选中,推送 \(\Delta=1\),总流量=3,总费用=10。
- 终止:残量网络中 \(t\) 不可达,算法结束。
最终结果:最大流=3,最小费用=10。