xxx 最大二分匹配的 Hopcroft-Karp 算法
字数 927 2025-11-19 21:35:25

xxx 最大二分匹配的 Hopcroft-Karp 算法

题目描述
给定一个二分图 G = (X ∪ Y, E),其中 X 和 Y 是不相交的顶点集合,E 是连接 X 和 Y 的边集合。最大二分匹配问题要求找到一个包含最多边的匹配 M ⊆ E,使得 M 中任意两条边都不共享公共顶点。

解题过程

1. 基本概念

  • 匹配:边集合 M ⊆ E,其中任意两条边不共享顶点
  • 最大匹配:包含边数最多的匹配
  • 交替路径:路径上的边交替属于匹配 M 和不属于匹配 M
  • 增广路径:起点和终点都是未匹配顶点的交替路径

2. 算法核心思想
Hopcroft-Karp 算法通过多轮 BFS 同时寻找多条最短增广路径,显著提高效率:

  • 时间复杂度 O(√|V| × |E|),比匈牙利算法的 O(|V|×|E|) 更优
  • 核心思想:在每轮迭代中同时寻找所有长度相同的最短增广路径

3. 算法步骤详解

步骤1:初始化

# 定义数据结构
match_X = {}  # X 集合中顶点的匹配对象
match_Y = {}  # Y 集合中顶点的匹配对象  
dist = {}     # BFS 中的距离标记

# 初始化所有顶点为未匹配状态
for x in X:
    match_X[x] = None
for y in Y: 
    match_Y[y] = None

步骤2:BFS 分层
从所有未匹配的 X 顶点开始进行 BFS,构建分层图:

def BFS():
    queue = deque()
    
    # 初始化距离
    for x in X:
        if match_X[x] is None:  # 未匹配的 X 顶点
            dist[x] = 0
            queue.append(x)
        else:
            dist[x] = float('inf')
    
    dist[None] = float('inf')  # 特殊标记
    
    while queue:
        x = queue.popleft()
        if dist[x] < dist[None]:
            for y in graph[x]:  # x 的所有邻居
                # 如果 y 已匹配,检查其匹配对象
                if match_Y[y] is not None:
                    next_x = match_Y[y]
                    if dist[next_x] == float('inf'):
                        dist[next_x] = dist[x] + 1
                        queue.append(next_x)
                else:
                    # 找到未匹配的 Y 顶点,路径结束
                    dist[None] = dist[x] + 1
    
    return dist[None] != float('inf')  # 是否存在增广路径

步骤3:DFS 寻找增广路径
在分层图上进行 DFS,寻找顶点不相交的增广路径:

def DFS(x):
    if x is None:
        return True
    
    for y in graph[x]:
        # 检查是否在分层图中且距离递增
        if match_Y[y] is not None:
            next_x = match_Y[y]
            if dist[next_x] == dist[x] + 1 and DFS(next_x):
                # 找到增广路径,更新匹配
                match_X[x] = y
                match_Y[y] = x
                return True
        else:
            # 直接连接到未匹配的 Y 顶点
            if dist[None] == dist[x] + 1:
                match_X[x] = y
                match_Y[y] = x
                return True
    
    dist[x] = float('inf')  # 标记为已访问
    return False

步骤4:主算法

def hopcroft_karp():
    matching = 0
    
    while BFS():  # 存在增广路径
        for x in X:
            if match_X[x] is None:  # 未匹配的 X 顶点
                if DFS(x):
                    matching += 1
    
    return matching

4. 执行过程示例
考虑二分图:

  • X = {1, 2, 3}, Y = {4, 5, 6}
  • 边:1-4, 1-5, 2-5, 3-5, 3-6

第1轮迭代:

  • BFS 找到距离为1的增广路径
  • DFS 可能找到路径 1-4,匹配:{1-4}
  • 匹配数:1

第2轮迭代:

  • BFS 找到距离为3的增广路径
  • DFS 可能找到路径 2-5-1-4-?(失败),然后找到路径 3-6
  • 匹配:{1-4, 3-6},匹配数:2

第3轮迭代:

  • BFS 找到距离为5的增广路径
  • DFS 找到路径 2-5-1-4-?(重新调整),最终得到最大匹配
  • 最终匹配:{1-5, 2-4, 3-6} 或类似,匹配数:3

5. 算法分析

  • 正确性:基于 Berge 引理 - 匹配是最大的当且仅当不存在增广路径
  • 效率:每轮 BFS 找到所有最短增广路径,最多需要 O(√|V|) 轮
  • 应用:任务分配、资源调度、网络流等场景

该算法通过分层 BFS 和并行 DFS 的高效组合,在二分图匹配问题中达到了接近线性的性能表现。

xxx 最大二分匹配的 Hopcroft-Karp 算法 题目描述 给定一个二分图 G = (X ∪ Y, E),其中 X 和 Y 是不相交的顶点集合,E 是连接 X 和 Y 的边集合。最大二分匹配问题要求找到一个包含最多边的匹配 M ⊆ E,使得 M 中任意两条边都不共享公共顶点。 解题过程 1. 基本概念 匹配:边集合 M ⊆ E,其中任意两条边不共享顶点 最大匹配:包含边数最多的匹配 交替路径:路径上的边交替属于匹配 M 和不属于匹配 M 增广路径:起点和终点都是未匹配顶点的交替路径 2. 算法核心思想 Hopcroft-Karp 算法通过多轮 BFS 同时寻找多条最短增广路径,显著提高效率: 时间复杂度 O(√|V| × |E|),比匈牙利算法的 O(|V|×|E|) 更优 核心思想:在每轮迭代中同时寻找所有长度相同的最短增广路径 3. 算法步骤详解 步骤1:初始化 步骤2:BFS 分层 从所有未匹配的 X 顶点开始进行 BFS,构建分层图: 步骤3:DFS 寻找增广路径 在分层图上进行 DFS,寻找顶点不相交的增广路径: 步骤4:主算法 4. 执行过程示例 考虑二分图: X = {1, 2, 3}, Y = {4, 5, 6} 边:1-4, 1-5, 2-5, 3-5, 3-6 第1轮迭代: BFS 找到距离为1的增广路径 DFS 可能找到路径 1-4,匹配:{1-4} 匹配数:1 第2轮迭代: BFS 找到距离为3的增广路径 DFS 可能找到路径 2-5-1-4-?(失败),然后找到路径 3-6 匹配:{1-4, 3-6},匹配数:2 第3轮迭代: BFS 找到距离为5的增广路径 DFS 找到路径 2-5-1-4-?(重新调整),最终得到最大匹配 最终匹配:{1-5, 2-4, 3-6} 或类似,匹配数:3 5. 算法分析 正确性:基于 Berge 引理 - 匹配是最大的当且仅当不存在增广路径 效率:每轮 BFS 找到所有最短增广路径,最多需要 O(√|V|) 轮 应用:任务分配、资源调度、网络流等场景 该算法通过分层 BFS 和并行 DFS 的高效组合,在二分图匹配问题中达到了接近线性的性能表现。