代表性面试主题

如何实现最小费用最大流?

编程题困难
Offer.cc 编辑团队发布 更新

题干

给定带容量和费用的有向网络、源点 s、汇点 t 和目标流量 limit,请实现发送尽可能多流量且总费用最小的算法,并说明负费用边、复杂度和测试。

题目与使用场景

网络每条边有容量和单位费用,要求从 s 到 t 发送最多 limit 的流量,并在流量相同的方案中费用最小。实现需要返回实际流量和费用,处理反向残量边、负费用、并行边、不可达和整数溢出。

面试官考察什么

  • 是否正确建立残量网络和反向边费用。
  • 能否用连续最短增广路或势能重标定处理负边。
  • 是否区分最大流量目标与最小费用次目标。
  • 能否给出复杂度、溢出边界和性质测试。

作答前的澄清问题

确认容量和费用是否为整数、是否允许负费用环、是否要求精确 limit、图规模和费用上界。若有负费用环,需说明模型是否允许无界降费,以及初始势能如何求得。

30 秒回答框架

每条输入边建立正向容量和反向容量为零的残量边,反向费用取相反数。反复在残量网络中寻找 s 到 t 的最短路,沿路增广瓶颈流量,直到达到 limit 或不存在路径。若边费用可能为负,先用 Bellman-Ford 求初始势能,之后用势能重标定让边费用非负,再用 Dijkstra。总复杂度取决于增广次数和最短路实现,不能只报普通最大流复杂度。

分步骤深入解答

1. 残量边结构

边记录终点、反向索引、剩余容量和费用。增广时减少正向容量、增加反向容量;费用乘以增广流量累加。反向边允许算法撤销早期选择,是费用最优的关键。

2. 最短路与势能

若所有费用非负,Dijkstra 足够。存在负费用但没有负环时,维护每个点的势能,使用重标定后的费用计算最短路,再更新势能。若初始费用含负值,不能直接把普通 Dijkstra 当作正确算法。

3. 增广与停止

每次增广量是 limit 剩余量、路径瓶颈和可选批量的最小值。路径不存在时停止并返回当前流量;若必须达到 limit,则报告不可行。费用用足够宽的整数类型,并在加法前检查乘法溢出。

高质量示范回答

我会用邻接表保存残量边,每次 addEdge 同时加入正向和反向边。主循环在残量容量为正的图上寻找最短 s 到 t 路径,沿路径增广并更新费用。无负费用时用 Dijkstra;有负费用但无负环时先求初始势能,再用 reduced cost 保持非负。每轮把增广量限制为目标剩余、路径瓶颈和边容量。无法继续时返回实际流量;若小于目标则标记不可行。测试覆盖反向撤销、并行边、零容量、负费用、断开图、达到部分流量、负环约束和大费用溢出。最小费用最大流与 OR-Tools 的模型一致,但具体复杂度要按增广次数、节点和边数说明,不能假设总是多项式于数值容量。

常见错误

  • 忘记加入反向边或把反向费用设为正数。
  • 在存在负费用边时直接使用 Dijkstra。
  • 找到一条最短路后只增广一单位,导致不必要的运行时间。
  • 把“最大流”与“达到目标流量的最小费用”混为一个排序条件。
  • 用窄整数累计费用,忽略大容量乘费用的溢出。

追问及应对

为什么反向边能改正之前的选择?

反向边代表撤回已发送的流量,并把相应费用取反。后续最短路可以走反向边,重排流量后得到更低总费用。

什么时候需要 Bellman-Ford?

初始残量图含负费用边且没有负环时,需要它或等价方法计算初始势能;之后 reduced cost 非负即可用 Dijkstra。

如果目标流量达不到怎么办?

停止并返回实际流量和费用,同时明确不可行。若业务必须满足目标,应在调用层回滚或选择备用网络,不能把部分流量冒充成功。

公开来源

同类题目

相关面试工具

用 Screenshot 处理算法题

截图题目后,按顺序看约束、解法、代码、边界条件和复杂度。

查看工具