匈牙利算法(Hungarian Algorithm)是一种解决二分图最大匹配(Maximum Bipartite Matching)问题的经典算法。在一个二分图中,该算法能够找到最大的匹配,即在给定的两组顶点中找到最大数量的边,使得每个顶点都最多与一个相邻顶点相连。
我们通过一个简单的例子来说明匈牙利算法的工作过程。
假设我们有一个二分图,如下所示:
1 2 3 4
A 3 2 0 1
B 2 4 1 0
C 1 3 2 1
D 0 2 5 2
这里,顶点分为两组:A, B, C, D是左边的未匹配顶点,1, 2, 3, 4是右边的未匹配顶点。图中的数字代表边的权重。
首先,我们进行初始化,将所有边的权重设为0,并为左边的每个顶点设定初始标号。在匈牙利算法中,左边的顶点对应于任务,右边的顶点对应于工人。初始时,我们将左边的顶点标号设为0。
1.初始化:
1 2 3 4
A 3 2 0 1
B 2 4 1 0
C 1 3 2 1
D 0 2 5 2
初始标号:
A: 0
B: 0
C: 0
D: 0
现在,我们从A开始寻找增广路径。我们可以从每个顶点出发,依次找到能够增加匹配数的路径。
2.寻找增广路径:
从A开始,我们看到A有两条边,分别指向3和4。我们首先看3:
A - 3,这条边没有匹配,我们可以将A与3匹配。
接着,我们看A - 4,这条边也没有匹配,我们可以将A与4匹配。
现在我们有两个匹配:A - 3和A - 4。
3.标记未匹配顶点:
现在,我们看B。B有边2和1,我们可以选择B - 1:
B - 1,这条边没有匹配,我们可以将B与1匹配。
现在我们有三个匹配:A - 3,A - 4,B - 1。
接着我们看C:
C - 3,这条边没有匹配,我们可以将C与3匹配。
现在我们有四个匹配:A - 3,A - 4,B - 1,C - 3。
最后我们看D:
D - 2,这条边没有匹配,我们可以将D与2匹配。
现在我们有五个匹配:A - 3,A - 4,B - 1,C - 3,D - 2。
现在,每个任务都已经分配给了一个工人,我们找到了一个最大匹配。
4.结果:
最终的最大匹配为:
A - 3
B - 1
C - 3
D - 2
这就是匈牙利算法的基本工作原理。在实际应用中,算法会根据实际情况不断更新顶点的标号,并寻找增广路径,直到无法再找到增广路径为止,从而得到最大的匹配。
算法步骤总结
- 初始化:将所有的边的权重设为0,并找到所有顶点的初始标号(后文详述)。
- 寻找增广路径:从左边的每个未匹配顶点开始,尝试通过增广路径的方式寻找增加匹配数的可能性。
- 标记未匹配顶点:如果找到增广路径,就将路径上的顶点标记为已匹配,并尝试为其他未匹配的顶点寻找增广路径。
- 更新标号:如果无法找到增广路径,则根据标号更新算法重新调整顶点的权重,以便寻找更多的增广路径。
- 重复步骤2-4,直到无法再找到增广路径为止。
代码实现:
class HungarianAlgorithm:
def __init__(self, graph):
self.graph = graph
self.rows = len(graph)
self.cols = len(graph[0])
self.matched = [-1] * self.cols # 存储匹配情况,初始化为-1
self.visited = [False] * self.cols # 用于DFS的访问标记
def find_matching(self):
match_count = 0 # 匹配数量
# 尝试为每个未匹配的左侧顶点寻找匹配
for i in range(self.rows):
self.visited = [False] * self.cols
if self.dfs(i):
match_count += 1
return match_count, self.matched
def dfs(self, u):
# 尝试匹配顶点u
for v in range(self.cols):
if self.graph[u][v] and not self.visited[v]:
self.visited[v] = True
# 如果顶点v未被匹配或者v的匹配顶点能够找到增广路径
if self.matched[v] == -1 or self.dfs(self.matched[v]):
self.matched[v] = u
return True
return False
# 示例用法
if __name__ == "__main__":
# 定义二分图的邻接矩阵表示
graph = [
[0, 1, 1, 0],
[1, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1]
]
# 创建匈牙利算法对象并执行匈牙利算法
hungarian = HungarianAlgorithm(graph)
max_matching, matching_result = hungarian.find_matching()
# 打印匹配结果
print("最大匹配数量:", max_matching)
print("匹配结果:", matching_result)
匈牙利算法详解:解决二分图最大匹配问题的过程与代码实现,

670





