本篇文章基于 Python 实现,另一篇文章基于 Java 实现:【运筹优化】最大二分匹配问题及两种算法详解 + Java代码实现
一、最大二分匹配问题
1.1 二分图
二分图,又称二部图,英文名叫 Bipartite graph。
二分图是什么?节点由两个集合组成,且两个集合内部没有边的图。
换言之,存在一种方案,将节点划分成满足以上性质的两个集合。
下图展示了一个二分图的示例:
1.2 最大二分匹配问题介绍
在最大二分匹配(MBM)问题中,给定一个二分图 G,即分左右两部分,两个部分内部的点没有边连接,要求选出一些边,使得这些边没有公共顶点,且边的数量最大。
上面的描述可能比较抽象,我们可以假想成男女配对。如下图所示,男女之间的连线代表他们互相之间有好感,假设你现在是一个媒婆,你的目标是在不违反男女双方自由意志的前提下,尽可能撮合出最多对的情侣。这就是最大二分匹配问题!
扫描二维码关注公众号,回复:
14670015 查看本文章
二、匈牙利算法
2.1 算法介绍
关于匈牙利算法的图解可以参考这篇博客:匈牙利算法-看这篇绝对就够了!
2.1 代码实现
def hungarian(graph):
# 初始化匈牙利树
tree = {
'V': set(), 'E': set()}
# 寻找增广路径
while True:
# 找到一条增广路径
path = find_augmenting_path(graph, tree)
if len(path['E']) == 0:
break
# 更新匈牙利树
tree['V'].update(path['V'])
tree['E'].update(path['E'])
# 返回最大匹配
return tree
def find_augmenting_path(graph, tree):
# 初始化增广路径
path = {
'V': set(), 'E': set()}
# 寻找增广路径
for v in graph['V']:
if v not in tree['V']:
# 寻找从v出发的增广路径
path = find_augmenting_path_from(graph, tree, v)
if len(path['E']) > 0:
break
# 返回增广路径
return path
def find_augmenting_path_from(graph, tree, v):
# 初始化增广路径
path = {
'V': set(), 'E': set()}
# 寻找增广路径
for e in graph['E']:
if e[0] == v and e[1] not in tree['V']:
# 找到一条增广路径
path['V'].add(v)
path['V'].add(e[1])
path['E'].add(e)
break
# 返回增广路径
return path
if __name__ == '__main__':
graph = {
'V': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'],
'E': [
('A', 'E'), ('A', 'I'), ('B', 'E'), ('B', 'F'), ('C', 'E'), ('C', 'H'), ('D', 'I'),
('E', 'A'), ('I', 'A'), ('E', 'B'), ('F', 'B'), ('E', 'C'), ('H', 'C'), ('I', 'D')
]
}
res = hungarian(graph)
print(res)
测试案例
输出
{
'V': {
'E', 'F', 'B', 'A', 'H', 'C', 'I', 'D'}, 'E': {
('D', 'I'), ('C', 'H'), ('B', 'F'), ('A', 'E')}}
最大匹配可视化
三、Hopcroft-karp 算法
暂未完成。
可以参考博客:二分图最大匹配之Hopcroft-Karp算法