前置知识: 算法与数据结构

网络流

00:00
3 min Advanced 2026/6/14

网络流算法:最大流 Ford-Fulkerson 方法、Edmonds-Karp 算法、残量图与增广路径。

1. 网络流基础

1.1 流网络定义

  • 有向图
  • ,汇
  • 容量
  • 流量 满足:
    • 容量约束:
    • 流量守恒:中间

1.2 最大流问题

求从 的最大流量

2. Ford-Fulkerson 方法

2.1 核心思想

反复寻找增广路径增加流量直到无法增广:

1. 初始化流为0
2. 在残量图中寻找 s→t 的增广路径
3. 沿路径增加流量(增加量为路径最小残量)
4. 更新残量图
5. 重复直到无增广路径

2.2 残量图

反向容量为当前流量允许”撤销”:

2.3 实现

from collections import deque

def edmonds_karp(capacity, s, t):
    n = len(capacity)
    flow = [[0] * n for _ in range(n)]
    max_flow = 0

    while True:
        # BFS 寻找增广路径
        parent = [-1] * n
        parent[s] = s
        queue = deque([s])

        while queue and parent[t] == -1:
            u = queue.popleft()
            for v in range(n):
                if parent[v] == -1 and capacity[u][v] - flow[u][v] > 0:
                    parent[v] = u
                    queue.append(v)

        if parent[t] == -1:
            break  # 无增广路径

        # 计算增广量
        aug = float('inf')
        v = t
        while v != s:
            u = parent[v]
            aug = min(aug, capacity[u][v] - flow[u][v])
            v = u

        # 更新流量
        v = t
        while v != s:
            u = parent[v]
            flow[u][v] += aug
            flow[v][u] -= aug
            v = u

        max_flow += aug

    return max_flow

3. Edmonds-Karp 算法

3.1 与 Ford-Fulkerson 的区别

Edmonds-Karp 使用 BFS 寻找最短增广路径保证多项式时间

Ford-Fulkerson: 增广路径选择任意 → 可能不收敛(容量为无理数时)
Edmonds-Karp:   BFS 最短路径 → O(VE^2)

3.2 复杂度分析

每次 BFS: O(E)
增广次数: O(VE)
总时间: O(VE^2)

关键证明: 最短增广路径长度单调不减
每条边最多成为关键边 O(V) 次

4. 最大流最小割定理

4.1 割的定义

顶点分为两部分,

4.2 定理

4.3 求最小割

def min_cut(capacity, flow, s):
    n = len(capacity)
    visited = [False] * n
    queue = deque([s])
    visited[s] = True

    while queue:
        u = queue.popleft()
        for v in range(n):
            if not visited[v] and capacity[u][v] - flow[u][v] > 0:
                visited[v] = True
                queue.append(v)

    # S = visited 的顶点, T = 未访问的顶点
    cut_edges = []
    for u in range(n):
        for v in range(n):
            if visited[u] and not visited[v] and capacity[u][v] > 0:
                cut_edges.append((u, v))
    return cut_edges

5. 应用

5.1 二分图最大匹配

def bipartite_matching(left_size, right_size, edges):
    n = left_size + right_size + 2
    s, t = 0, n - 1
    capacity = [[0] * n for _ in range(n)]

    # 源到左部
    for i in range(1, left_size + 1):
        capacity[s][i] = 1

    # 右部到汇
    for j in range(left_size + 1, n - 1):
        capacity[j][t] = 1

    # 左到右的边
    for u, v in edges:
        capacity[u + 1][v + left_size + 1] = 1

    return edmonds_karp(capacity, s, t)

5.2 算法对比

| 算法 | 时间复杂度 | 特 | | -------------- | ---------- | ---------- | --- | ---------- | | Ford-Fulkerson | | 可能不收敛 | | Edmonds-Karp | | BFS 最短路 | | Dinic | | 分层 | | Push-Relabel | | 实现 | | ISAP | | 简化 Dinic |

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式