二分匹配大总结——Bipartite Graph Matchings[LnJJF]

二分匹配——Bipartite Graph Matchings[LnJJF]

**前言:**二分匹配的核心就在于求MAX最大匹配数,但是题目不会很直接地让你求MAX最大匹配数,而又可能让你求MIN,如最小顶点覆盖数,DAG图的最小路径覆盖数;也有可能让你求另一种MAX最大独立集。但是题目不论怎么变化,有关二分图的题目,基本都可以转化为求最大匹配数的问题。抓住这点,非常重要。

认识:什么是二分图?

​ 图论中的一种特殊模型。通俗点讲,左边点集U,右边点集V,U有5个点,V有4个点,U的点只和V的点相连,不内部相连,就可以算是一个二分/二部图了。

图1.典型二分图

理解:现实模型如何与二分图相互转化?

如何判断能否转化?

​ 现实模型必须有三个特点,一是有且仅有两个(或者可以创造)具有根本性差异的主体(有两个点集),二是这两个主体中有不同的状态/样态(点集内部有多个独立点),三是主体中的不同样态内部无关联,但与另一样态内部有关联(点集内部的点不相连,两个点集的点相连)。

​ 例如,我们最典型的婚配模型。婚配模型的问题是这样的,有X个男生,Y个女生,大家都是异性恋,男生与女生之间有许多双向暗恋的关系,一个男生可以与多个女生,一个女生也可以与多个男生有双向暗恋关系。假设双向暗恋的男女都能婚配成功,问最多有能有几对婚配成功?

​ 在婚配模型中,我们可以看到这三个特点。一是差异性主体,男女就是两个差异性主体。二是主体中有不同的样态,如男1,男2,如女1,女2,都是不同的。三是主体中的不同样态内部无关联,但与另一样态内部有关联,即问题中所说的,大家都是异性恋,并且男女之间有许多双向暗恋的关系。三个条件都满足,那么就可以将现实模型向二分图转化。

图2.有向无环图的转化示例

​ 另外有一种DAG图的最小不相交路径覆盖问题,比较特殊,原基础只有一个主体,是通过创造第二个主体来实现双主体,如图2所示,具体创造的方法,会于后文介绍。

能够转化的话,如何转化?

​ 能够转化,问题就很简单了。差异性主体,作为独立的点集,放在两端;同一个主体的不同样态,作为题目中的多个点,放在同一个主体下面,按题目次序排列;最后就是找关系,这个关系要么是能够相互匹配,即彼此之间有题意关联的,进行连接。

应用:已知一个二分图,求最大匹配数的方法是什么?

匈牙利算法示例解析

图3.匈牙利算法示例图

​ 答案是匈牙利算法,匈牙利算法,是一种用增广路径求二分图最大匹配的算法。我们同样还是以婚配问题为例,来讲解这个算法。倘若我们有两男三女,可婚配的关系如图3所示,我们可以比较清楚地判断出,最大匹配的方案,就是简单的“男1配女2”+“男2配女1”。但是,这只是凭我们的感觉,计算机并没有我们的感觉,那该怎么做呢?答案是植入这样一个执行套路。

从上到下遍历至女1,女1可选,选择女1
男1
女1
图4.男1选中女1
从上到下遍历至女1,女1不可选,看一看女1的男朋友男1能不能换一个女朋友?
男1
女1
男2
图5.男2希望与女1匹配,看看女1的男朋友有没有其它的选择
男1不再访问女1,遍历至女2,判断,男1可以换女朋友女1为女2
男2与女1匹配成功
男1
女2
男2
女1
图6.男1继续刚才的遍历到女2,可以换为女2,男1男2同时配对成功

匈牙利算法求二分图最大匹配的通用思路

​ 从上面案例的执行套路,我们可以得出一个匈牙利算法对于一切二分图求最大匹配的简单流程图。

匈牙利算法求二分图最大匹配数,算法思路图
选中左1,找右点集匹配对象
找到右点集第一个可匹配对象,进行匹配,匹配成功
选中左2,找右点集第一个可匹配对象,进行匹配
如果左2的第一个可匹配对象,目前没有匹配对象,匹配成功
如果左2的第一个可匹配对象,目前已有匹配对象,回到左2希望匹配的对象,它的当前对象
左2希望匹配的对象,它的当前对象如果能更改对象,左2配对成功
左2希望匹配的对象,它的当前对象不能更改对象.
左2继续找右点集第二三...个可匹配对象,直到匹配成功或失败
选中左3,4,5...,重复左2的操作,直至左边点遍历完毕
匹配成功的次数,即为我们要求的最大匹配数
图7.匈牙利算法求二分图最大匹配数的思路流程图

匈牙利算法核心部分代码展示(C++)——通用代码模板

...
bool dfs(int zuo){//输入左边的点名 
    for(int you=0;you<youmax;you++){//遍历右边的点 
        if(!vis[you]&&g[zuo][you]){//如果不是原来的匹配对象,并且可连接 
            vis[you]=1;//防止判断左点能不能改匹配的时候,又把原先的匹配对象选中,从而进入死循环 
            if(linker[you]==-1||dfs(linker[you])){
                //可连接的基础上,右点i没有匹配对象或者右点i的匹配对象可以改匹配对象 
                linker[you]=zuo;//i和u进行连接 
                return true;//表示匹配成功 
            }
        }
    }
    return false;
}
int main(){
    ...
        int cnt=0;//匹配数初始化为0 
        memset(linker,-1,sizeof(linker));//初始化右点的匹配对象为-1,代表都没有匹配对象 
        for(int zuo=0;zuo<zuomax;zuo++){//遍历左点 
            memset(vis,0,sizeof(vis));//初始化每个左点的访问数组为0 
            if(dfs(zuo))cnt++;//如果左点连接成功,匹配数加一 
        }       
    ...
}

活用:那些题目不是求最大匹配数,但是可以转化为求最大匹配数来做?

开始的时候,我们已经说了,很多时候并非是直接求最大匹配数。我们更多的时候,往往是转化为最大匹配数的思路来求解。接下来,我将给出几个常见的转化类型,并讲解为何可以转化,让我们活用匈牙利算法。

1. 最小顶点覆盖数=最大匹配数

什么是最小顶点覆盖?

​ 在二分图中,选中最少的点,关联所有的边,此时的选中的最少点数,就是二分图的最小顶点覆盖数。

图8.最小顶点覆盖数讲解图
为什么最小顶点覆盖数=最大匹配数?

图9.最小顶点覆盖数讲解图2

​ 在图9中,我们不妨先求一下,这个图中的最大匹配数是多少?利用刚才所说的匈牙利算法,我们会得到最终的匹配结果是”男1配女2“+”男2配女1“+”男4配女3”(匹配结果不唯一,但是匹配数为一,我们在此随机举最大匹配上的一种情况)。最大匹配数为3。我们只需要证明,在3条边的每条边上选择1个顶点,总共选择3个对应的顶点一定会覆盖所有的边,即可证明最大匹配数=最小顶点覆盖数。在3条匹配边每条边上选1个点的时候,有一定的要求:如果这两个点中的某个点,有与非匹配点(即图中的蓝圈圈出的点)有连边的话,则只能选择该点;否则任意选。

​ 根据选择要求,我们选出了男4,女1和女2三个点。我们直接根据图,可以看出它们确实是覆盖了所有的边。这是一个例子。但具体如何证明呢?

​ 证明:我们在最大匹配数为M的情况下,在M条匹配边中,每条边挑选出1个点,挑选原则还是同上,即优先选择有与非匹配点(即途中的蓝圈圈出的点)有连边的点,挑选出M个点。

​ 接下来,我们要证明这M个点,能够覆盖所有的边。

​ 对于所有的边,无非就两种情况,第一种它是匹配边(红色边),另一种它是非匹配边(未标红黑边)。

​ 匹配边已经被覆盖,无需多言。

​ 对于非匹配边,也无非就两种情况,第一种是这条边的两个点,有一个是匹配点(红圈圈出的点),有一个是非匹配点(蓝圈圈出的点),这条边必然被我们构造的点集覆盖;第二种是这条边的两个点,都是非匹配点(蓝圈圈出的点),如果真的存在,也就是说没覆盖到,那么这两个点直接相连,最大匹配数应该还要再增加,而不等于M,这显然是与我们求出的最大匹配数为M是矛盾的。

​ 综上所述,最大匹配数M=最小顶点覆盖数M。

有什么现实模型,是问最小顶点覆盖的呢?

​ 最小顶点覆盖数的本质,就在于**“去点消关联”**。还是以刘老师的题目为例子。

图10.严禁早恋例题图

​ 题目大意:有上图男生集与女生集,两者连接代表可以双发可以发展成恋爱关系,为了防止出现早恋现象,学校要开除几个学生,使得所有人不可能发展成恋爱关系,求最少要开出几名学生。

​ 这道题,本质上问的,就是在这个二分图中,去除最少的点,消除所有的关联,本质上,就是选择最少的点,覆盖所有的边。总结成一句话,最小顶点覆盖数,题目的意思,一定有“去点消关联”的意思,如在这题,去点就是开除学生,消关联就是让所有人不可能发展成恋爱关系,读题读到“去点消关联”,那么最小顶点覆盖就八九不离十了,那么匈牙利算法求最大匹配数也就八九不离十了。

2. 最大独立集=顶点数-最小顶点覆盖数=顶点数-最大匹配数

什么是最大独立集?

​ 我们刚才讲到,最小顶点覆盖数的题目,就是去点消关联。最大独立集,本质上就是在此过程上再进一步。也就是“去点消关联,求剩余”因为去点消关联之后,剩余的不就是没有关联的吗,没有关联的,不就是独立的吗?而最多的独立顶点个数,就被我们称为最大独立集。

为什么最大独立集=顶点数-最小顶点覆盖数

​ 一开始,二分图是有关联的,有边相连。最小顶点覆盖数,就是我们实现所有点独立,最少去除的点数,那么顶点总数减去这些点数,不就是最多的独立点数吗?这个相比于之前的证明,更好理解一些。

有什么现实模型,是问最小顶点覆盖的呢?

​ 回到刚才的图10,我们把问题改成,开除一定量的学生,实现最多的学生不可能发展成恋爱,求最多的学生数,即是求此处的最大独立集。

3. DAG图的最小不相交路径覆盖=顶点数-最大匹配数

什么是DAG图?

​ DAG图,英文名为Directed Acyclic Graph,翻译为“有向无环图”。即图是单向,并且不会形成回路的图。

什么是DAG图的最小不相交路径覆盖?
1
3
2
4
5
图11.DAG图的最小不相交路径覆盖示例图

​ DAG图的最小不相交路径覆盖,就是在DAG图中,在路径不相交的前提下,用最少的路径覆盖全图。

​ 例如,在图11中,我们不能选择1→3→4+2→3→5两条路径来覆盖全图,因为它们有一个路径相交点3。

​ 但是,我们可以选择1→3→4+2+5这三条路径来覆盖全图(特殊地,单独的点也可以作为一条路径,不过它的路径长度为0而已)。

​ 路径不相交的前提下,最少的覆盖全图的路径数条数,就是最小不相交路径覆盖。如图11的最小不相交路径覆盖就是3。

​ 我的问题是什么?为什么13之后再23不能算匹配?1和3匹配成功了,2和3就不能再匹配。不支持3脚踏两只船。原本有3个点 1 2 3 1和2连了 变成1条路径 和一个点3 1和3连了 变成2条路径 0个点

为什么DAG图的最小不相交路径覆盖=顶点数-最大匹配数?

在这里插入图片描述

图12.图11的初始状态

在这里插入图片描述

图13.构建DAG图的起点终点二分图

​ 文章的一开始,我们提到,可以通过自行创建另一个主体的方式,来建立一个DAG图的二分图,从而解决DAG图的最小不相交路径覆盖问题。那么我们就以左点集为起点,右点集为终点,构建一个起点终点二分图。

​ 起点终点二分图中,一个起点只能与一个终点单匹配机制,正是这种最小不相交路径覆盖中,不相交的体现

​ **试想,如果起点1连终点3,起点2能再连终点3,终点3同时与起点1和2匹配,那就不符合单个匹配原则,也就不属于二分图最大匹配问题了。**因此,在这样的二分图中,每匹配成功一对,就相当于是找到一条不相交路径。也就是说,在这个二分图中,最大匹配数,就相当于原先DAG图中,最多不相交的路径条数。

​ 现在进入证明阶段,假设原先我们是n个独立顶点(如图12所示),那么我们最少需要n条不相交路径来覆盖这n个独立顶点。每匹配一条不相交路径,本质上就是将两条路径合成为一条路径,总最少需要路径数减1。那么最开始需要用n条不相交路径覆满全图,在已知最多不相交的路径条数为构建二分图的最大匹配数的情况下,只需再减去最大匹配数,就是最少不相交路径覆盖数了!

后记

​ 第一次写知识点总结,整整一天的非娱乐时间基本都在写了,终于在凌晨0:40肝完啦。累并快乐着,尤其是最后的DAG图想不明白,看了网上许多资料也想不明白,自己加入起点终点构图思路后,再能够解释清楚之后,还是很有成就感的。

​ 蒟蒻自语,写博客好爽…

参考

《2021杭电ACM-LCY算法培训》(安利刘老师的课!)

最小顶点覆盖证明思路来源

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值