最大流问题的重标记与前移算法(Relabel-to-Front Algorithm)
字数 1840 2025-12-12 12:26:55

最大流问题的重标记与前移算法(Relabel-to-Front Algorithm)

题目描述
给定一个流网络,包含源点 s 和汇点 t,以及 n 个顶点、m 条有向边,每条边有容量。要求计算从 s 到 t 的最大流。你将实现一种高效的 push-relabel 算法变体——Relabel-to-Front 算法,时间复杂度为 O(n³)。

解题过程

1. 前置知识:Push-Relabel 框架
Push-Relabel 算法是最大流问题的另一类解法,不维护流的守恒性,而是维护每个顶点的“高度”和“超额流”。核心操作:

  • 推流(Push):将超额流从当前顶点推向高度较低的邻居。
  • 重标记(Relabel):若当前顶点有超额流但无法推给任何较低邻居,则抬高其高度。

Relabel-to-Front 算法在此基础上,通过一个“顶点列表”的顺序处理,将复杂度优化到 O(n³)。

2. 算法数据结构

  • 容量 c(u, v):边 (u, v) 的容量。
  • 流量 f(u, v):当前流。
  • 超额流 e(u):顶点 u 的净流入超出其流出部分(源点、汇点除外)。
  • 高度 h(u):顶点 u 的高度,h(s)=n,h(t)=0,初始时其他顶点高度为 0。
  • 邻接表 N(u):记录所有邻居(包括反向边)。
  • 当前弧 current[u]:记录下一次要检查的邻居在 N(u) 中的位置,用于跳过已处理的边。

3. 算法初始化

  • 初始化所有流量 f(u, v) = 0。
  • 对源点 s 的每条出边 (s, v),执行 f(s, v) = c(s, v),e(v) = c(s, v),e(s) 减去相应值。
  • 初始化 h(s) = n,其他顶点高度 h(u) = 0。
  • 构建顶点列表 L:包含所有顶点(除 s 和 t),顺序任意。

4. 算法主循环
维护一个指针指向 L 中的当前顶点 u。重复以下步骤直到处理完 L 中所有顶点:

  • 记 u 的原始高度为 old_height。
  • 当 e(u) > 0 时,尝试推流或重标记:
    a. 从 current[u] 开始扫描邻接表 N(u),对每条边 (u, v):
    • 若 h(u) == h(v) + 1 且边 (u, v) 有剩余容量(c(u,v)-f(u,v) > 0),则执行 push(u, v)。
    • 推送量 Δ = min(e(u), 剩余容量)。
    • 更新 f(u, v) 和 e(u)、e(v),若 v 不是 s 或 t 且 e(v) 刚变为正,则将 v 移到 L 的头部。
      b. 若扫描完所有邻居后 e(u) > 0,则执行 relabel(u):
    • 将 h(u) 设为 1 + min{ h(v) | (u,v) 有剩余容量 }。
      c. 若重标记后 h(u) 增加,则将 u 移到 L 的头部,重置指针指向 L 的新头部。
  • 若 e(u) 变为 0 或 u 的高度未变,则移动指针到 L 中的下一个顶点。

5. 推流与重标记的细节

  • Push 操作需更新正向边和反向边流量。
  • Relabel 操作需检查所有邻接边,找出有剩余容量的邻居的最小高度。

6. 正确性保证

  • 高度引理:始终有 h(u) ≤ h(v) + 1 对于任意有剩余容量的边 (u, v)。
  • 高度函数确保无环,且最终汇点高度不变,源点高度始终为 n。
  • 当除 s、t 外无超额流时,流即为最大流。

7. 时间复杂度分析

  • 重标记次数最多 2n² 次(每个顶点高度不超过 2n)。
  • 饱和推流(使边满)最多 O(nm) 次。
  • 非饱和推流最多 O(n³) 次(每次推流使当前顶点在 L 中前移)。
  • 总复杂度 O(n³)。

8. 举例说明
考虑一个简单网络:s→a (cap=3),s→b (cap=2),a→t (cap=2),a→b (cap=1),b→t (cap=3)。

  • 初始化:从 s 推流到 a、b,e(a)=3, e(b)=2,高度 h(s)=4, 其他为 0。
  • 处理顶点 a:推 2 到 t,推 1 到 b(因 h(a)=0 不高于 h(b),需先重标记 a 为 1),更新超额流。
  • 依次处理顶点,直到所有 e(u)=0,得到最大流 4。

9. 总结
Relabel-to-Front 是 push-relabel 算法的高效实现,通过维护顶点列表的顺序,避免全局扫描,将复杂度优化到 O(n³),适合稠密图的最大流计算。掌握其高度管理、推流条件与列表更新是关键。

最大流问题的重标记与前移算法(Relabel-to-Front Algorithm) 题目描述 给定一个流网络,包含源点 s 和汇点 t,以及 n 个顶点、m 条有向边,每条边有容量。要求计算从 s 到 t 的最大流。你将实现一种高效的 push-relabel 算法变体——Relabel-to-Front 算法,时间复杂度为 O(n³)。 解题过程 1. 前置知识:Push-Relabel 框架 Push-Relabel 算法是最大流问题的另一类解法,不维护流的守恒性,而是维护每个顶点的“高度”和“超额流”。核心操作: 推流(Push) :将超额流从当前顶点推向高度较低的邻居。 重标记(Relabel) :若当前顶点有超额流但无法推给任何较低邻居,则抬高其高度。 Relabel-to-Front 算法在此基础上,通过一个“顶点列表”的顺序处理,将复杂度优化到 O(n³)。 2. 算法数据结构 容量 c(u, v):边 (u, v) 的容量。 流量 f(u, v):当前流。 超额流 e(u):顶点 u 的净流入超出其流出部分(源点、汇点除外)。 高度 h(u):顶点 u 的高度,h(s)=n,h(t)=0,初始时其他顶点高度为 0。 邻接表 N(u):记录所有邻居(包括反向边)。 当前弧 current[ u ]:记录下一次要检查的邻居在 N(u) 中的位置,用于跳过已处理的边。 3. 算法初始化 初始化所有流量 f(u, v) = 0。 对源点 s 的每条出边 (s, v),执行 f(s, v) = c(s, v),e(v) = c(s, v),e(s) 减去相应值。 初始化 h(s) = n,其他顶点高度 h(u) = 0。 构建顶点列表 L:包含所有顶点(除 s 和 t),顺序任意。 4. 算法主循环 维护一个指针指向 L 中的当前顶点 u。重复以下步骤直到处理完 L 中所有顶点: 记 u 的原始高度为 old_ height。 当 e(u) > 0 时,尝试推流或重标记: a. 从 current[ u ] 开始扫描邻接表 N(u),对每条边 (u, v): 若 h(u) == h(v) + 1 且边 (u, v) 有剩余容量(c(u,v)-f(u,v) > 0),则执行 push(u, v)。 推送量 Δ = min(e(u), 剩余容量)。 更新 f(u, v) 和 e(u)、e(v),若 v 不是 s 或 t 且 e(v) 刚变为正,则将 v 移到 L 的头部。 b. 若扫描完所有邻居后 e(u) > 0,则执行 relabel(u): 将 h(u) 设为 1 + min{ h(v) | (u,v) 有剩余容量 }。 c. 若重标记后 h(u) 增加,则将 u 移到 L 的头部,重置指针指向 L 的新头部。 若 e(u) 变为 0 或 u 的高度未变,则移动指针到 L 中的下一个顶点。 5. 推流与重标记的细节 Push 操作需更新正向边和反向边流量。 Relabel 操作需检查所有邻接边,找出有剩余容量的邻居的最小高度。 6. 正确性保证 高度引理:始终有 h(u) ≤ h(v) + 1 对于任意有剩余容量的边 (u, v)。 高度函数确保无环,且最终汇点高度不变,源点高度始终为 n。 当除 s、t 外无超额流时,流即为最大流。 7. 时间复杂度分析 重标记次数最多 2n² 次(每个顶点高度不超过 2n)。 饱和推流(使边满)最多 O(nm) 次。 非饱和推流最多 O(n³) 次(每次推流使当前顶点在 L 中前移)。 总复杂度 O(n³)。 8. 举例说明 考虑一个简单网络:s→a (cap=3),s→b (cap=2),a→t (cap=2),a→b (cap=1),b→t (cap=3)。 初始化:从 s 推流到 a、b,e(a)=3, e(b)=2,高度 h(s)=4, 其他为 0。 处理顶点 a:推 2 到 t,推 1 到 b(因 h(a)=0 不高于 h(b),需先重标记 a 为 1),更新超额流。 依次处理顶点,直到所有 e(u)=0,得到最大流 4。 9. 总结 Relabel-to-Front 是 push-relabel 算法的高效实现,通过维护顶点列表的顺序,避免全局扫描,将复杂度优化到 O(n³),适合稠密图的最大流计算。掌握其高度管理、推流条件与列表更新是关键。