最小成本最大流问题的网络单纯形算法
字数 3073 2025-12-11 00:36:50
最小成本最大流问题的网络单纯形算法
题目描述
给定一个有向图 \(G = (V, E)\),每条边有容量 \(u(e)\) 和非负成本 \(c(e)\),以及源点 \(s\) 和汇点 \(t\)。目标是找到从 \(s\) 到 \(t\) 的最大流,并且在所有最大流中,总成本最小。这就是最小成本最大流问题。本题目要求用网络单纯形算法求解,这是一种基于线性规划单纯形法思想的专用算法,比通用线性规划求解器更高效。
1. 算法思想
网络单纯形算法将最小成本最大流问题建模为线性规划问题,但利用图的特殊结构进行优化:
- 将流量分配表示为生成树结构(称为树解)。
- 通过交换边(进基边与离基边)逐步改进解,直到满足最优性条件。
- 核心是避免维护完整的单纯形表,而是直接在图上操作,利用树结构的性质快速计算。
2. 问题建模
设决策变量 \(f(e)\) 表示边 \(e\) 上的流量,则线性规划模型为:
\[\text{最小化} \quad \sum_{e \in E} c(e) f(e) \]
约束:
- 容量约束:\(0 \le f(e) \le u(e)\)。
- 流量守恒(除 \(s, t\) 外):\(\sum_{e \in \text{in}(v)} f(e) = \sum_{e \in \text{out}(v)} f(e)\)。
- 最大流目标:从 \(s\) 流出的总量等于最大流值 \(F^*\)(可先求最大流,或作为算法结果)。
网络单纯形法通常先找一个可行树解,然后迭代优化。
3. 初始可行树解
我们需要一个生成树,包含所有顶点,且树边对应的流量满足容量约束和守恒。常用方法:
- 加入人工边:从汇点 \(t\) 到源点 \(s\) 加一条无限容量、零成本的边,形成一个循环。
- 初始树:选择所有顶点与“根”(通常为 \(t\) )通过人工边或虚拟边连接,形成一棵树,并设初始流量为0(或可行流)。
- 更实用的方法:先用最大流算法求一个最大流(忽略成本),再用树重构得到初始树解。
4. 树解的结构
- 树 \(T\) 是图的生成树,非树边集合为 \(L\)(下边)和 \(U\)(上边)。
- 每条非树边 \(e\) 的流量要么是 0(如果 \(e \in L\)),要么是 \(u(e)\)(如果 \(e \in U\))。
- 树边流量可通过守恒唯一确定(因为树有 \(|V|-1\) 条边,对应 \(|V|-1\) 个独立方程)。
- 为方便,常引入一个根节点(root),并定义每个节点的势(potential)\(\pi(v)\),满足:对每条树边 \((i,j)\),有 \(\pi(j) = \pi(i) - c(i,j)\)(假设树边方向朝向根时调整符号)。
5. 最优性条件
定义边 \((i,j)\) 的简化成本(reduced cost)为:
\[\bar{c}_{ij} = c_{ij} - \pi(i) + \pi(j) \]
在树解中:
- 对所有树边,简化成本为 0(由势的定义保证)。
- 最优条件为:对每条非树边 \(e\):
- 如果 \(f(e) = 0\)(在 \(L\) 中),则 \(\bar{c}_e \ge 0\)。
- 如果 \(f(e) = u(e)\)(在 \(U\) 中),则 \(\bar{c}_e \le 0\)。
若某边不满足,则可通过将其加入树(进基)来改进。
6. 迭代步骤
步骤1:检查最优条件
- 计算势 \(\pi\):从根开始,按树边递推(根势设为0)。
- 计算所有非树边的简化成本 \(\bar{c}_e\)。
- 找一条违反最优条件的边:
- 若 \(f(e)=0\) 但 \(\bar{c}_e < 0\),则 \(e\) 可进基以增加流量(减少成本)。
- 若 \(f(e)=u(e)\) 但 \(\bar{c}_e > 0\),则 \(e\) 可进基以减少流量(减少成本)。
- 若无违反,当前解即最优,结束。
步骤2:进基与离基选择
- 设违反边为 \(e^* = (p,q)\)。将 \(e^*\) 加入树,形成一个圈(cycle)。
- 沿圈调整流量:若 \(e^*\) 原来流量为0,则沿圈增加流量;若原来满容量,则减少流量。
- 调整量 \(\delta\) 受限于圈上边的容量:
- 若增加流量,则顺向边不能超容量,逆向边不能为负。
- 若减少流量,则顺向边不能为负,逆向边不能超容量。
- 确定 \(\delta\) 后,圈上某条边会达到边界(0 或容量),该边即为离基边(从树中移除)。
步骤3:更新树与势
- 从树中移除离基边,加入进基边 \(e^*\),得到新树。
- 更新势:由于树结构改变,重新计算势(可通过遍历子树调整)。
7. 示例说明
考虑简单图:\(V=\{s,a,t\}, E=\{(s,a), (a,t), (s,t)\}\)。
- 容量:\(u(s,a)=2,u(a,t)=2,u(s,t)=1\)。
- 成本:\(c(s,a)=1, c(a,t)=2, c(s,t)=5\)。
目标:最小成本最大流(最大流为3)。
初始化树:选树边为 \((s,a),(a,t)\),非树边 \((s,t)\) 流量=1(满容量)。
- 设根为 \(t\),计算势:\(\pi(t)=0, \pi(a)=\pi(t)+c(a,t)=2, \pi(s)=\pi(a)+c(s,a)=3\)。
- 检查 \((s,t)\):\(\bar{c}_{s,t}=5-3+0=2>0\),但流量=1(满容量),违反最优条件(应 \(\bar{c} \le 0\))。
- 进基:将 \((s,t)\) 加入树,形成圈 \(s \to t \to a \to s\)。
- 调整:减少 \((s,t)\) 流量(因它满容量且 \(\bar{c}>0\)),沿圈增加其他边流量。调整量 \(\delta=1\)(受限于 \((s,t)\) 最多减1)。
- 离基:调整后 \((s,t)\) 流量=0,离基。
- 新树:\((s,a),(a,t)\) 不变,势重新计算,检查最优条件满足。
最终流:\(f(s,a)=2,f(a,t)=2,f(s,t)=1\),总成本= \(2\cdot1+2\cdot2+1\cdot5=11\)。
继续迭代可进一步优化:实际上最优解为全部流走 \(s-a-t\),总成本= \(3\cdot(1+2)=9\)。
8. 算法复杂度
- 每次迭代:找违反边 \(O(|E|)\),更新树和势 \(O(|V|)\)。
- 迭代次数:最坏情况下是指数级的,但在实践中通常很快(平均多项式时间)。
- 实际中常用强多项式的SSP或Cost Scaling,但网络单纯形在特定问题上效率很高。
9. 关键要点
- 网络单纯形是单纯形法在流问题的特化,利用树结构避免矩阵运算。
- 核心操作:势计算、简化成本检查、圈流调整、树更新。
- 可处理有负成本边(但需避免负圈)。
- 是许多商业优化软件(如CPLEX、Gurobi)中求解最小费用流的内核之一。