当前位置: 首页 > article >正文

【有啥问啥】二分图(Bipartite Graph)算法原理详解

二分图

二分图(Bipartite Graph)算法原理详解

引言

二分图(Bipartite Graph),又称二部图,是图论中的一个重要概念。在实际应用中,二分图模型经常用于解决如匹配问题、覆盖问题和独立集问题等。本文将详细解析二分图的基本概念、性质、判定方法,以及求解最大匹配问题的匈牙利算法,并探讨其在实际中的应用。

  • 传送门链接: 图的数据结构(Graph Data Structures):深入探索与应用

1. 基本概念

1.1 定义

G = ( V , E ) G=(V,E) G=(V,E)是一个无向图,如果顶点集 V V V可以分割为两个互不相交的子集 A A A B B B,且图中的每条边 ( i , j ) (i,j) (i,j)所关联的两个顶点 i i i j j j分别属于这两个不同的顶点集(即 i ∈ A , j ∈ B i \in A, j \in B iA,jB),则称图 G G G为一个二分图。

1.2 性质

  1. 无向图G为二分图的充分必要条件

    • G中至少包含两个顶点。
    • G中所有回路的长度均为偶数。
  2. 二分图的匹配

    • G = < V , E > G=<V, E> G=<V,E>为二分图,如果 M ⊆ E M \subseteq E ME,并且 M M M中任意两条边都没有公共端点(即没有边共用一个顶点),则称 M M M G G G的一个匹配。
  3. 最大匹配

    • 在所有匹配中,边数最多的匹配称为最大匹配。
  4. 完备匹配与完全匹配

    • X X X中的所有顶点都是匹配 M M M中的端点,则称 M M M X X X的完备匹配。
    • M M M既是 X X X-完备匹配又是 Y Y Y-完备匹配,则称 M M M G G G的完全匹配(也称完美匹配)。

2. 判定方法

2.1 原理

无向图 G G G为二分图的一个充要条件是 G G G中不存在奇圈(即所有回路的长度均为偶数)。这一性质是二分图判定的核心依据。

2.2 实现方法

  1. 染色法

    • 任意选择一个顶点并赋予颜色1(或称为红色),放入集合 U U U
    • 将该顶点的所有未染色邻居顶点赋予颜色2(或称为蓝色),放入集合 V V V
    • 依次对集合 V V V中的每个顶点重复上述过程,直到所有顶点都被染色或发现矛盾(即存在边连接的两个顶点颜色相同)。
    • 如果所有顶点都被成功染色,则图是二分图;否则,不是二分图。
  2. 代码实现(DFS版本):

    def dfs(graph, color, vertex, color_value):
     """
     Perform DFS to color the graph and check if it's bipartite.
     """
     color[vertex] = color_value
     for neighbor in range(len(graph)):
         if graph[vertex][neighbor]:
             if color[neighbor] == -1:
                 if not dfs(graph, color, neighbor, 1 - color_value):
                     return False
             elif color[neighbor] == color_value:
                 return False
     return True
    
     def is_bipartite(graph):
         """
         Check if the given graph is bipartite.
         """
         n = len(graph)
         if n == 0:
             return True  # An empty graph is trivially bipartite
         
         color = [-1] * n
         for i in range(n):
             if color[i] == -1:
                 if not dfs(graph, color, i, 0):
                     return False
         return True
    

3. 匈牙利算法求解最大匹配

3.1 原理

匈牙利算法通过不断寻找增广路(也称为增广轨或交错轨)来增加匹配中的边数,直到无法找到新的增广路为止,此时得到的匹配即为最大匹配。

3.2 实现步骤

  1. 初始化匹配集 M M M为空集。
  2. 对每个未匹配点 u u u,执行:
    • u u u出发进行深度优先搜索(DFS),寻找一条增广路。
    • 如果找到增广路,则进行增广操作(即反转路径上边的匹配状态),并更新匹配集 M M M
    • 重复上述过程,直到无法找到新的增广路为止。

3.3 代码实现

def dfs(graph, match, visited, u):
    """
    Depth-first search to find an augmenting path in the bipartite graph.
    
    :param graph: Adjacency matrix of the bipartite graph.
    :param match: Current matching state.
    :param visited: Visited nodes in the current DFS.
    :param u: Current node to start DFS from.
    :return: True if an augmenting path is found, False otherwise.
    """
    for v in range(len(graph[u])):
        if graph[u][v] and not visited[v]:
            visited[v] = True
            if match[v] == -1 or dfs(graph, match, visited, match[v]):
                match[v] = u
                return True
    return False

def hungarian(graph):
    """
    Hungarian algorithm to find the maximum matching in a bipartite graph.
    
    :param graph: Adjacency matrix of the bipartite graph.
    :return: The size of the maximum matching.
    """
    n = len(graph)
    match = [-1] * n  # Initialize match array with -1 (no matches initially)
    result = 0
    
    for u in range(n):
        visited = [False] * n  # Reset visited array for each new DFS
        if dfs(graph, match, visited, u):
            result += 1
    
    return result

4. 应用场景

二分图算法在很多实际场景中都有应用,例如:

  • 推荐系统:通过建立用户和物品的二分图,利用最大匹配算法为用户推荐最感兴趣的物品。
  • 任务分配:在生产或项目管理中,将任务与可执行者建立二分图关系,利用匹配算法优化资源分配。
  • 社交网络:分析社交网络中的用户与兴趣之间的关系,找到最佳的匹配组合。

总结

二分图算法是图论中的一项重要技术,其应用范围广泛。本文详细解析了二分图的基本概念、性质、判定方法,以及求解最大匹配的匈牙利算法。通过理解和应用这些算法,我们可以有效地解决许多实际问题。希望本文能为读者在二分图算法的学习和应用中提供帮助。


http://www.kler.cn/news/327086.html

相关文章:

  • SpringMVC源码-AbstractUrlHandlerMapping处理器映射器将实现Controller接口的方式定义的路径存储进去
  • 健康生活,从日常细节开始
  • NVLM多模态 LLM 在图像和语言任务中的表现优于 GPT-4o
  • Oracle数据恢复—异常断电导致Oracle数据库报错的数据恢复案例
  • 第167天:应急响应-日志自动提取分析项目_ELK_Logkit_LogonTracer_Anolog等
  • Mysql高级篇(下)——日志
  • Microsoft Edge 五个好用的插件
  • MySQL存储过程循环操作
  • LVGL 笔记
  • SpringBoot3+Swagger3(最新版springdoc-openapi教程)
  • 组合优化与凸优化 学习笔记5 对偶拉格朗日函数
  • 21 vue3之发布npm插件(hook自定义指令)
  • 国产RISC-V案例分享,基于全志T113-i异构多核平台!
  • 【刷题6】一维前缀和、二维前缀和
  • 学习VTK的目的和方法
  • 速盾:cdn加速什么好?
  • 【Linux探索学习】第二弹——Linux的基础指令(中)——夯实基础第二篇
  • 25考研咨询周开启,西安电子科技大学是否改考408??
  • HarmonyOS Next系列之水波纹动画特效实现(十三)
  • ClickHouse入库时间与实际相差8小时问题
  • 升级FreeBSD13.2到14.1-RELEASE
  • 树和二叉树知识点大全及相关题目练习【数据结构】
  • golang 获取证书的生效及过期时间
  • 【论文笔记】Flamingo: a Visual Language Model for Few-Shot Learning
  • Redis篇(应用案例 - 附近商户)(持续更新迭代)
  • Pgsql 数据库操作
  • 【运动控制】关于GPIO通用输入口是NPN型数字输入
  • Grafana指标汉化
  • 【测试-BUG篇】软件测试的BUG知识你了解多少呢?
  • 自动驾驶系列—DOW(开门预警):让每一次开门都更安心