1. 什么是二分图
二分图(Bipartite Graph),又称二部图,是图论中的一类特殊图。它的定义是:设图 G = (V, E) 是一个无向图,如果顶点集 V 可以划分为两个互不相交的子集 A 和 B,使得图中每条边的两个端点分别属于 A 和 B,则称图 G 为二分图。
换句话说,二分图中的所有边都连接着两个不同集合中的顶点,同一个集合内部的顶点之间不存在边。这种结构在现实世界中非常常见,例如:
- 学生选课:学生和课程分别构成两个集合,边表示选课关系。
- 任务分配:工人和任务构成两个集合,边表示工人能胜任该任务。
- 社交网络:用户和兴趣标签构成两个集合,边表示用户关注该标签。
二分图之所以重要,是因为许多实际问题都可以抽象为二分图模型,进而利用图论算法高效求解。
2. 二分图的性质与判定
判断一个图是否为二分图,最常用的方法是染色法。其核心思想是:从任意一个顶点出发,将其染成一种颜色(如红色),然后将其所有邻接顶点染成另一种颜色(如蓝色),再依次对邻接顶点的邻接顶点染色。如果在染色过程中,某个顶点已经被染成与当前应染颜色不同的颜色,则说明图中存在奇数环,该图不是二分图。
染色法通常借助广度优先搜索(BFS)或深度优先搜索(DFS)实现,时间复杂度为 O(V + E),其中 V 是顶点数,E 是边数。
二分图有一个重要性质:一个图是二分图,当且仅当它不包含奇数长度的环。这个性质是染色法正确性的理论基础。
from collections import deque
def is_bipartite(graph):
n = len(graph)
color = [-1] * n # -1 表示未染色,0 和 1 表示两种颜色
for i in range(n):
if color[i] == -1:
color[i] = 0
queue = deque([i])
while queue:
node = queue.popleft()
for neighbor in graph[node]:
if color[neighbor] == -1:
color[neighbor] = 1 - color[node]
queue.append(neighbor)
elif color[neighbor] == color[node]:
return False
return True
3. 二分图的最大匹配
在二分图中,匹配是指一组边,其中任意两条边都没有公共顶点。最大匹配则是包含边数最多的匹配。求解二分图最大匹配的经典算法是匈牙利算法(Hungarian Algorithm),其时间复杂度为 O(V × E)。
匈牙利算法的核心思想是增广路径:从左侧集合的一个未匹配顶点出发,寻找一条交替经过未匹配边和已匹配边的路径,如果路径的终点是右侧集合的未匹配顶点,则沿着该路径翻转匹配状态,即可使匹配数加一。重复这一过程,直到找不到增广路径为止。
def hungarian(graph, n_left, n_right):
match_right = [-1] * n_right # 右侧顶点匹配的左侧顶点编号
def dfs(u, visited):
for v in graph[u]:
if not visited[v]:
visited[v] = True
if match_right[v] == -1 or dfs(match_right[v], visited):
match_right[v] = u
return True
return False
result = 0
for u in range(n_left):
visited = [False] * n_right
if dfs(u, visited):
result += 1
return result
4. 二分图的应用场景
二分图及其匹配算法在工程实践中有着广泛的应用,以下是几个典型场景:
- 任务分配问题:将 n 个任务分配给 m 个工人,每个工人只能完成部分任务,目标是让尽可能多的任务被完成。
- 课程安排:将课程安排到时间段,避免同一学生同时上多门课。
- 推荐系统:将用户与物品建模为二分图,通过匹配或图嵌入算法进行个性化推荐。
- 棋盘覆盖问题:用多米诺骨牌覆盖棋盘上的特定格子,可转化为二分图最大匹配问题。
此外,二分图还与最小点覆盖、最大独立集等经典问题紧密相关。根据柯尼希定理(König's Theorem),在二分图中,最大匹配数等于最小点覆盖数,这一结论在算法设计中经常被用来相互转化问题。
5. 总结
二分图是图论中一类结构优美且应用广泛的图。本文从定义出发,介绍了二分图的染色判定方法、匈牙利算法求解最大匹配,以及典型的应用场景。掌握二分图模型,能够帮助我们在面对许多实际优化问题时,快速找到高效的算法路径。
建议读者在理解算法原理后,动手实现一遍染色法和匈牙利算法,并结合 LeetCode 或算法竞赛中的相关题目进行练习,以加深对二分图的理解。

1091

被折叠的 条评论
为什么被折叠?



