基于线性规划的图最小费用流问题的消圈算法求解示例
字数 4254 2025-12-10 13:05:08
基于线性规划的图最小费用流问题的消圈算法求解示例
我将为您讲解最小费用流问题的一个经典算法——消圈算法。这个算法基于一个直观原理:如果一个流是最小费用流,那么其残差网络中不存在负费用圈。
1. 问题描述
我们有一个有向图 \(G=(V, E)\),其中每条边 \(e \in E\) 有两个参数:
- 容量 \(u_e \ge 0\),表示该边允许通过的最大流量。
- 单位费用 \(c_e\),表示通过该边每单位流量所需的费用。
此外,图中每个顶点 \(v \in V\) 有一个净需求 \(b(v)\):
- 如果 \(b(v) > 0\),则 \(v\) 是“需求点”或“汇点”,需要接收 \(b(v)\) 单位的流量。
- 如果 \(b(v) < 0\),则 \(v\) 是“供应点”或“源点”,可以提供 \(-b(v)\) 单位的流量。
- 如果 \(b(v) = 0\),则是转运点。
我们要求一个可行流 \(f: E \to \mathbb{R}_{\ge 0}\),满足:
- 容量约束:对所有边 \(e\),有 \(0 \le f(e) \le u_e\)。
- 流量平衡约束:对每个顶点 \(v\),流入量减去流出量等于其净需求。即:
\[
\sum_{(u, v) \in E} f(u, v) - \sum_{(v, w) \in E} f(v, w) = b(v)
\]
在满足以上条件的可行流中,最小费用流问题的目标是找到总费用最小的流,即最小化:
\[\sum_{e \in E} c_e f(e)
\]
2. 解题过程:消圈算法
消圈算法的核心思想是从任意一个可行流开始,不断在其残差网络中寻找负费用圈,然后沿这个圈增加流量,从而减少总费用,直到不存在负费用圈为止。
步骤 0: 初始化
找到一个初始可行流 \(f\)。这可以通过求解一个只关心可行性(不关心费用)的最大流问题得到,或者如果问题结构简单(如单源单汇),可直接构造一个零流(如果满足平衡条件)。
步骤 1: 构造残差网络 \(G_f\)
对于当前流 \(f\),构造残差网络 \(G_f = (V, E_f)\)。
- 对于原图的每一条边 \(e = (u, v) \in E\):
- 如果 \(f(e) < u_e\)(即还有剩余容量),则在 \(G_f\) 中加入一条正向边 \((u, v)\),其残差容量为 \(r(u, v) = u_e - f(e)\),残差费用为 \(c'(u, v) = c_e\)。
- 如果 \(f(e) > 0\)(即已有流量可以退回),则在 \(G_f\) 中加入一条反向边 \((v, u)\),其残差容量为 \(r(v, u) = f(e)\),残差费用为 \(c'(v, u) = -c_e\)(因为退回流量相当于“赚回”原来的费用)。
步骤 2: 检测负费用圈
在残差网络 \(G_f\) 中,寻找是否存在总费用为负的圈(简称“负圈”)。这可以通过Bellman-Ford算法或SPFA算法来实现,因为它们可以在有向图中检测负环。
- 如果不存在负费用圈,根据最小费用流的理论,当前的流 \(f\) 就是最小费用流。算法结束。
- 如果存在一个负费用圈 \(C\),进入步骤3。
步骤 3: 沿圈增流
设找到的负费用圈为 \(C = (v_1, v_2, ..., v_k, v_1)\),其总费用 \(\sum_{e \in C} c'(e) < 0\)。
- 计算这个圈上每条边的最大可调整流量 \(\delta\):
\[
\delta = \min_{e \in C} \{ r(e) \}
\]
其中 \(r(e)\) 是 \(G_f\) 中边 \(e\) 的残差容量。
- 对这个圈 \(C\) 上的每条边进行调整:
- 如果 \(e\) 是 \(G_f\) 中的正向边(对应原图的边 \((u, v)\)),则将该边上的流量增加 \(\delta\),即 \(f(u, v) := f(u, v) + \delta\)。
- 如果 \(e\) 是 \(G_f\) 中的反向边(对应原图的边 \((v, u)\)),则相当于将原边 \((v, u)\) 上的流量减少 \(\delta\),即 \(f(v, u) := f(v, u) - \delta\)。
- 由于是沿着一个圈增流,每个顶点的流入流出变化量相互抵消,因此流量平衡约束始终保持满足。容量约束也因 \(\delta\) 的定义而保持满足。
步骤 4: 更新流和费用
计算这次调整带来的费用变化:
\[\Delta Cost = \delta \cdot \left( \sum_{e \in C} c'(e) \right)
\]
因为圈的总费用为负,所以 \(\Delta Cost < 0\),总费用严格下降。
更新总费用:\(TotalCost := TotalCost + \Delta Cost\)。
然后,返回到步骤1,基于新的流 \(f\) 重新构造残差网络。
3. 算法正确性理解
- 关键定理:一个可行流是最小费用流,当且仅当它的残差网络中不存在负费用圈。
- 充分性(为什么没有负圈就是最优):如果存在另一个费用更低的可行流 \(f'\),那么流之差 \(f' - f\) 可以表示为残差网络中一组圈流的叠加。由于 \(f'\) 的总费用更低,其中至少包含一个总费用为负的圈,这与假设矛盾。
- 必要性(为什么有负圈就可以改进):如果在 \(G_f\) 中存在一个负费用圈,那么沿着这个圈发送一个正的流量 \(\delta\),可以在保持流量平衡和容量约束的前提下,直接降低总费用。因此当前流 \(f\) 不是最优的。
4. 一个简单的计算示例
考虑一个简单的三角形图,帮助理解。
图结构:
- 顶点:\(V = \{1, 2, 3\}\)
- 边:\(E = \{(1,2), (2,3), (1,3)\}\)
- 参数:每条边的格式为 \((容量, 单位费用)\)
- \((1,2): (2, 1)\)
- \((2,3): (1, 1)\)
- \((1,3): (1, 3)\)
- 净需求:\(b(1) = -1\) (供应1单位), \(b(2) = 0\), \(b(3) = 1\) (需求1单位)。
目标:找到从1到3的最小费用流,流量值为1。
算法执行过程:
-
初始化:从零流开始,\(f = 0\)。零流可行吗?检查平衡:顶点1供应1单位,但零流无法送达顶点3,所以零流不可行。我们需要一个初始可行流。一个简单的方法是:从1直接送1单位到3,费用为3。所以初始可行流 \(f_{12}=0, f_{23}=0, f_{13}=1\)。总费用 = 3。
-
第一次迭代:
- 构造残差网络 \(G_f\):
- 边(1,2):流量0,容量2,有正向边(1,2),\(r=2, c'=1\)。
- 边(2,3):流量0,容量1,有正向边(2,3),\(r=1, c'=1\)。
- 边(1,3):流量1,容量1。有反向边(3,1),\(r=1, c'=-3\)(因为退回流量节省费用)。
- 检测负圈:寻找圈。比如圈 \(1 \rightarrow 2 \rightarrow 3 \rightarrow 1\)。
- 费用 = \(c'(1,2) + c'(2,3) + c'(3,1) = 1 + 1 + (-3) = -1 < 0\)。找到一个负费用圈!
- 沿圈增流:圈上最小残差容量 \(\delta = min\{2, 1, 1\} = 1\)。
- 沿(1,2)增加流量1:\(f_{12} = 1\)。
- 沿(2,3)增加流量1:\(f_{23} = 1\)。
- 沿(3,1)是反向边,意味着将原边(1,3)的流量减少1:\(f_{13} = 0\)。
- 更新后流:\(f_{12}=1, f_{23}=1, f_{13}=0\)。总费用变化 = \(1 * (-1) = -1\),新总费用 = \(3 - 1 = 2\)。
-
第二次迭代:
- 构造新的残差网络 \(G_f\):
- 边(1,2):流量1,容量2。有正向边(1,2),\(r=1, c'=1\);有反向边(2,1),\(r=1, c'=-1\)。
- 边(2,3):流量1,容量1。有反向边(3,2),\(r=1, c'=-1\)。
- 边(1,3):流量0,容量1。有正向边(1,3),\(r=1, c'=3\)。
- 检测负圈:尝试找圈。例如,圈 \(1 \rightarrow 2 \rightarrow 1\) 的费用 = \(1 + (-1) = 0\),非负。圈 \(1 \rightarrow 3 \rightarrow 2 \rightarrow 1\) 的费用 = \(3 + 1 + (-1) = 3 > 0\)。经检查,不存在总费用为负的圈。
- 算法终止。
最终解:最小费用流为从1到2送1单位,从2到3送1单位。总费用为 \(1*1 + 1*1 = 2\)。这确实比初始方案(费用3)更优。
5. 算法特点与总结
- 优点:
- 概念清晰,直接基于“无负圈即最优”这一优美理论。
- 实现相对简单,只需能找负圈和更新流。
- 缺点:
- 最坏情况下的时间复杂度可能较差。如果每次只消除一个负圈且减少的费用很小,迭代次数可能非常多(伪多项式时间)。
- 严重依赖于初始可行流的质量。如果初始流费用很高,可能需要很多次消圈操作。
- 关联:消圈算法是许多更高效的最小费用流算法(如“最小平均圈消去法”、“代价缩放算法”)的理论基础。
此算法生动地展示了如何将优化问题(最小化总费用)转化为一个在残差网络中不断“纠错”(消除负圈)的过程。
基于线性规划的图最小费用流问题的消圈算法求解示例 我将为您讲解最小费用流问题的一个经典算法——消圈算法。这个算法基于一个直观原理:如果一个流是最小费用流,那么其残差网络中不存在负费用圈。 1. 问题描述 我们有一个有向图 \( G=(V, E) \),其中每条边 \( e \in E \) 有两个参数: 容量 \( u_ e \ge 0 \),表示该边允许通过的最大流量。 单位费用 \( c_ e \),表示通过该边每单位流量所需的费用。 此外,图中每个顶点 \( v \in V \) 有一个 净需求 \( b(v) \): 如果 \( b(v) > 0 \),则 \( v \) 是“需求点”或“汇点”,需要接收 \( b(v) \) 单位的流量。 如果 \( b(v) < 0 \),则 \( v \) 是“供应点”或“源点”,可以提供 \( -b(v) \) 单位的流量。 如果 \( b(v) = 0 \),则是转运点。 我们要求一个 可行流 \( f: E \to \mathbb{R}_ {\ge 0} \),满足: 容量约束 :对所有边 \( e \),有 \( 0 \le f(e) \le u_ e \)。 流量平衡约束 :对每个顶点 \( v \),流入量减去流出量等于其净需求。即: \[ \sum_ {(u, v) \in E} f(u, v) - \sum_ {(v, w) \in E} f(v, w) = b(v) \] 在满足以上条件的可行流中, 最小费用流问题 的目标是找到总费用最小的流,即最小化: \[ \sum_ {e \in E} c_ e f(e) \] 2. 解题过程:消圈算法 消圈算法的核心思想是 从任意一个可行流开始,不断在其残差网络中寻找负费用圈,然后沿这个圈增加流量,从而减少总费用,直到不存在负费用圈为止 。 步骤 0: 初始化 找到一个初始可行流 \( f \)。这可以通过求解一个只关心可行性(不关心费用)的最大流问题得到,或者如果问题结构简单(如单源单汇),可直接构造一个零流(如果满足平衡条件)。 步骤 1: 构造残差网络 \( G_ f \) 对于当前流 \( f \),构造残差网络 \( G_ f = (V, E_ f) \)。 对于原图的每一条边 \( e = (u, v) \in E \): 如果 \( f(e) < u_ e \)(即还有剩余容量),则在 \( G_ f \) 中加入一条 正向边 \( (u, v) \),其 残差容量 为 \( r(u, v) = u_ e - f(e) \), 残差费用 为 \( c'(u, v) = c_ e \)。 如果 \( f(e) > 0 \)(即已有流量可以退回),则在 \( G_ f \) 中加入一条 反向边 \( (v, u) \),其 残差容量 为 \( r(v, u) = f(e) \), 残差费用 为 \( c'(v, u) = -c_ e \)(因为退回流量相当于“赚回”原来的费用)。 步骤 2: 检测负费用圈 在残差网络 \( G_ f \) 中,寻找是否存在 总费用为负的圈 (简称“负圈”)。这可以通过Bellman-Ford算法或SPFA算法来实现,因为它们可以在有向图中检测负环。 如果 不存在 负费用圈,根据最小费用流的理论,当前的流 \( f \) 就是最小费用流。 算法结束 。 如果 存在 一个负费用圈 \( C \),进入步骤3。 步骤 3: 沿圈增流 设找到的负费用圈为 \( C = (v_ 1, v_ 2, ..., v_ k, v_ 1) \),其总费用 \( \sum_ {e \in C} c'(e) < 0 \)。 计算这个圈上每条边的 最大可调整流量 \( \delta \): \[ \delta = \min_ {e \in C} \{ r(e) \} \] 其中 \( r(e) \) 是 \( G_ f \) 中边 \( e \) 的残差容量。 对这个圈 \( C \) 上的每条边进行调整: 如果 \( e \) 是 \( G_ f \) 中的正向边(对应原图的边 \( (u, v) \)),则将该边上的流量增加 \( \delta \),即 \( f(u, v) := f(u, v) + \delta \)。 如果 \( e \) 是 \( G_ f \) 中的反向边(对应原图的边 \( (v, u) \)),则相当于将原边 \( (v, u) \) 上的流量减少 \( \delta \),即 \( f(v, u) := f(v, u) - \delta \)。 由于是沿着一个圈增流,每个顶点的流入流出变化量相互抵消,因此流量平衡约束始终保持满足。容量约束也因 \( \delta \) 的定义而保持满足。 步骤 4: 更新流和费用 计算这次调整带来的 费用变化 : \[ \Delta Cost = \delta \cdot \left( \sum_ {e \in C} c'(e) \right) \] 因为圈的总费用为负,所以 \( \Delta Cost < 0 \),总费用严格下降。 更新总费用:\( TotalCost := TotalCost + \Delta Cost \)。 然后,返回到 步骤1 ,基于新的流 \( f \) 重新构造残差网络。 3. 算法正确性理解 关键定理 :一个可行流是最小费用流, 当且仅当 它的残差网络中不存在负费用圈。 充分性(为什么没有负圈就是最优) :如果存在另一个费用更低的可行流 \( f' \),那么流之差 \( f' - f \) 可以表示为残差网络中一组圈流的叠加。由于 \( f' \) 的总费用更低,其中至少包含一个总费用为负的圈,这与假设矛盾。 必要性(为什么有负圈就可以改进) :如果在 \( G_ f \) 中存在一个负费用圈,那么沿着这个圈发送一个正的流量 \( \delta \),可以在保持流量平衡和容量约束的前提下,直接降低总费用。因此当前流 \( f \) 不是最优的。 4. 一个简单的计算示例 考虑一个简单的三角形图,帮助理解。 图结构 : 顶点:\( V = \{1, 2, 3\} \) 边:\( E = \{(1,2), (2,3), (1,3)\} \) 参数:每条边的格式为 \( (容量, 单位费用) \) \( (1,2): (2, 1) \) \( (2,3): (1, 1) \) \( (1,3): (1, 3) \) 净需求:\( b(1) = -1 \) (供应1单位), \( b(2) = 0 \), \( b(3) = 1 \) (需求1单位)。 目标 :找到从1到3的最小费用流,流量值为1。 算法执行过程 : 初始化 :从零流开始,\( f = 0 \)。零流可行吗?检查平衡:顶点1供应1单位,但零流无法送达顶点3,所以零流不可行。我们需要一个初始可行流。一个简单的方法是:从1直接送1单位到3,费用为3。所以初始可行流 \( f_ {12}=0, f_ {23}=0, f_ {13}=1 \)。总费用 = 3。 第一次迭代 : 构造残差网络 \( G_ f \): 边(1,2):流量0,容量2,有正向边(1,2),\( r=2, c'=1 \)。 边(2,3):流量0,容量1,有正向边(2,3),\( r=1, c'=1 \)。 边(1,3):流量1,容量1。有反向边(3,1),\( r=1, c'=-3 \)(因为退回流量节省费用)。 检测负圈:寻找圈。比如圈 \( 1 \rightarrow 2 \rightarrow 3 \rightarrow 1 \)。 费用 = \( c'(1,2) + c'(2,3) + c'(3,1) = 1 + 1 + (-3) = -1 < 0 \)。找到一个负费用圈! 沿圈增流:圈上最小残差容量 \( \delta = min\{2, 1, 1\} = 1 \)。 沿(1,2)增加流量1:\( f_ {12} = 1 \)。 沿(2,3)增加流量1:\( f_ {23} = 1 \)。 沿(3,1)是反向边,意味着将原边(1,3)的流量减少1:\( f_ {13} = 0 \)。 更新后流:\( f_ {12}=1, f_ {23}=1, f_ {13}=0 \)。总费用变化 = \( 1 * (-1) = -1 \),新总费用 = \( 3 - 1 = 2 \)。 第二次迭代 : 构造新的残差网络 \( G_ f \): 边(1,2):流量1,容量2。有正向边(1,2),\( r=1, c'=1 \);有反向边(2,1),\( r=1, c'=-1 \)。 边(2,3):流量1,容量1。有反向边(3,2),\( r=1, c'=-1 \)。 边(1,3):流量0,容量1。有正向边(1,3),\( r=1, c'=3 \)。 检测负圈:尝试找圈。例如,圈 \( 1 \rightarrow 2 \rightarrow 1 \) 的费用 = \( 1 + (-1) = 0 \),非负。圈 \( 1 \rightarrow 3 \rightarrow 2 \rightarrow 1 \) 的费用 = \( 3 + 1 + (-1) = 3 > 0 \)。经检查, 不存在 总费用为负的圈。 算法终止 。 最终解 :最小费用流为从1到2送1单位,从2到3送1单位。总费用为 \( 1 1 + 1 1 = 2 \)。这确实比初始方案(费用3)更优。 5. 算法特点与总结 优点 : 概念清晰,直接基于“无负圈即最优”这一优美理论。 实现相对简单,只需能找负圈和更新流。 缺点 : 最坏情况下的时间复杂度可能较差。如果每次只消除一个负圈且减少的费用很小,迭代次数可能非常多(伪多项式时间)。 严重依赖于初始可行流的质量。如果初始流费用很高,可能需要很多次消圈操作。 关联 :消圈算法是许多更高效的最小费用流算法(如“最小平均圈消去法”、“代价缩放算法”)的理论基础。 此算法生动地展示了如何将优化问题(最小化总费用)转化为一个在残差网络中不断“纠错”(消除负圈)的过程。