您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

详解匈牙利算法与二分图匹配

时间:2020-08-18 15:49:07  来源:  作者:

今天是算法与数据结构专题的第31篇文章,我们一起来聊聊二分图匹配与匈牙利算法。

在上一篇文章当中我们介绍了一个有趣的稳定婚姻问题,模拟了男男女女配对的婚恋场景,并且研究了一下让匹配更加稳定的Gale-Shapley算法。如果错过了这篇文章的同学可以从下方的传送门回顾一下婚姻稳定问题的具体内容。

学算法还能指导找对象?是的,这就是大名鼎鼎的稳定婚姻算法​mp.weixin.qq.com

在上一篇文章的末尾我们曾经提到过,婚姻匹配问题本质上来说其实是二分图匹配的问题。那么什么又是二分图匹配呢?二分图匹配的问题又该通过什么算法来解决呢?下面就让我们一起从最基础的概念开始。

二分图匹配

二分图的概念很简单,就是在一个无向图当中,所有的点可以分成两个子集。这两个子集当中的点各自互不相交,并且图当中的所有边关联的顶点都属于两个不同的集合。单纯用语言描述有一点吃力,其实我们找一张图看一下就明白了。

详解匈牙利算法与二分图匹配

 

在上图当中很明显左边的竖着的三个点是一个集合,右边竖着的三个点是另外一个集合。两个集合之间有边相连,集合内部互不连通。

匹配与最大匹配

在二分图当中,如果我们选择了一条边就会连通对应的两个点。这也就构成了一个匹配,我们规定一个顶点最多只能构成一个匹配,也就是说所有的匹配之间没有公共的点。

对于一张二分图而言,构成的匹配数量可以是不同的,其中匹配数量最多的情况叫做最大匹配。如果所有顶点都有了匹配,那么就称这种情况为完美匹配。

今天要介绍的匈牙利算法就是一种用来完成二分图最大匹配的算法。

匈牙利算法

匈牙利我们都知道是一个国家的名字,这和算法的发明人有关。匈牙利算法的发明人Edmonds在1965年提出了匈牙利算法,我也不知道为什么算法发明人是匈牙利的就叫匈牙利算法,也没见过其他以国家命名的算法,是因为匈牙利人提出的算法太少了吗?

匈牙利算法的核心原理非常简单,就是寻找增广路径,从而达成最大匹配。

我们用通俗易懂的语言来解释一下算法的含义,我们还用上面那张图作为举例。我们首先将左边的1和右侧的a,左边的2和右侧的b节点匹配。

详解匈牙利算法与二分图匹配

 

这样当我们想要匹配左侧的3号节点的时候发现了一个问题,那就是能够和3号节点构成匹配的a和b节点都已经被占据了。所以3号节点无法构成匹配,但是我们观察一下图就能发现,如果1和2号节点稍微调整一下匹配的情况,其实是可以给3号节点挪出一个位置来的。

具体怎么操作呢?

我们遍历3号节点能够匹配的节点,首先找到a节点,发现a节点已经被占用了。于是我们找到a节点匹配的节点也就是1号节点,试着让它重新找一个匹配,给3号节点挪出位置来。于是我们递归安排1号节点,我们遍历到b节点,发现b节点也被占用了。于是我们同样递归与b节点匹配的2号节点,看看2号节点能不能找到新的坑腾出一个位置来。

我们观察一下发现2号节点可以和c节点构成匹配,腾出位置来给1号,这样1号就能腾出位置来给3号节点了。所以最终的匹配结果就成了这样:

详解匈牙利算法与二分图匹配

 

其中蓝线是调整匹配之前的结果,红色是调整之后的结果。

本质上来说,匈牙利算法就是一个调整匹配的过程。通过递归调用的形式去尝试调整已经占据了发生冲突位置的匹配,腾出位置来给右面的节点。

我们把匈牙利算法的原理和Gale-Shapley算法比较一下,有没有发现什么?其实这两个算法的核心原理是一样的,在GS算法当中我们是先由男生发起追求,尽可能构成匹配。然后单身的男生再一轮一轮发起表白,如果有更好的匹配则断开之前的匹配。在稳定婚姻问题当中我们定义了匹配的好坏,而在原生的二分图匹配的问题当中匹配是不分好坏的。如果我们抛开匹配好坏不谈,把优质男生抢占劣质男生女朋友的过程看成是匹配调整的过程,那么其实这两个算法的核心几乎是一样的。

唯一不同的是GS算法是一轮一轮的迭代,直到所有节点完成匹配为止。因为在婚姻匹配问题当中是一定有完美匹配的解的,而二分图匹配的问题当中,完美匹配的情况可能不一定存在。所以我们不能使用这样迭代的方式进行,而使用递归进行更好一些。换句话来说匈牙利算法研究的是二分图匹配的通解,而GS算法只是二分图算法的一个特殊案例。

代码实现

匈牙利算法的思路如果学会了,代码其实非常简单,就是一个简单的递归调用。

def find_match(x):
    for i in range(n):
        if graph[x][i] and not tried[i]:
            tried[i] = True
            if match[i] == -1 or find_match(match[i]):
                match[i] = x
                return True
            
     return False


for i in range(n):
    tried = [0 for _ in range(n)]
    find_match(i)

我们再试着用匈牙利算法来做一下婚姻稳定问题,因为在婚姻稳定问题当中每两个异性之间都有配对的可能,所以不需要再判断连通的情况了。并且构成的匹配有质量好坏的差别,所以需要去掉是否尝试过的判断。

girls_matched = [-1 for _ in range(n)]
boys_round = [0 for _ in range(n)]
boys_matched = [-1 for _ in range(n)]


def find_match(x):
 for i in range(n):
        idx = girls[i].index(x)
        mate = girls_matched[i]
        mate_id = n+1 if mate == -1 else girls[i].index(mate)
        # 如果女孩i没有对象或者是对象比x男生弱
        if mate == -1 or (idx < mate_id and find_match(girls_matched[i])):
            girls_matched[i] = x
            boys_matched[x] = i
            return True
                
    return False


for i in range(n):
    # 对i男生进行匹配
    find_match(i)

我们运行一下这段代码:

详解匈牙利算法与二分图匹配

 

结果当然是正确的,但是如果我们尝试用GS算法演示一下会发现这两个算法的结果不一样。这是为什么呢?原因也很简单,因为GS算法男生追求的顺序是自己喜好的顺序,而匈牙利算法当中是按照编号顺序,所以因此得到的结果不同。

总结

关于匈牙利算法的原理与介绍就到这里结束了,对于二分图匹配问题来说我们有很多种算法可以解决,但是匈牙利算法是其中比较简单易于理解与实现的一种。如果我们将它与之前介绍的GS算法相对比,可以发现很多共性和连通的部分。文中只是简单介绍了一些,如果仔细研究下去还会发现很多有趣的点。

今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。

- END -

本文始发于公众号: TechFlow



Tags:匈牙利算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
今天是算法与数据结构专题的第31篇文章,我们一起来聊聊二分图匹配与匈牙利算法。在上一篇文章当中我们介绍了一个有趣的稳定婚姻问题,模拟了男男女女配对的婚恋场景,并且研究了...【详细内容】
2020-08-18  Tags: 匈牙利算法  点击:(157)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(9)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(19)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(13)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(37)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条