二分图常见问题总结

本文全面解析二分图的概念,包括二分图的判定、匹配、最小点覆盖、最大独立集、最长反链及带权匹配等核心算法。通过实例讲解匈牙利算法、KM算法、网络流求解等技巧,深入浅出地阐述二分图在图论中的应用。

1.二分图

二分图是指一个图能够分成两部分,每一部分的点之间互相没有连边
比如说这个东西就是一个二分图

因为他能够被分成 u u u v v v两部分, u u u中的点相互之间没有连边, v v v中的点相互之间也没有连边
二分图也叫做二部图,偶图等等
在OI中,几乎所有二分图的题目都可以用网络流来实现,但是二分图本身是有非常优秀的算法的,下面我们来介绍一下

2.二分图的判定

2.1 定义法判定二分图

二分图的判定方法就是基于他的定义的
显然,根据定义,一个二分图不能存在奇环
如果存在奇环的话显然不是一个二分图,这个大家可以参照上面的图理解一下,应该不难
那么这道题的内容就转化成了判断一个图是否有奇环
这个做法怎么做呢?
我们常见的做法是进行黑白染色
给有边连接的两个点染成不同的颜色,如果dfs(bfs)的过程中,出现一个点的标记颜色和我们要标的颜色不同的话,那么就出现了奇环,这个图就不是二分图
当然判断二分图还有其他方法比如拓扑排序之类的,但是这种做法有一个优点就是他最后直接为我们分好了两部分
简单的放一下这种做法的代码

inline void dfs(int u,int c){
   
   
	color[u]=c;
	for(int i=head[u];~i;i=e[i].next){
   
   
		int v=e[i].to;
		if(color[v]==-1)dfs(v,c^1);
		else if(color[v]==c){
   
   
			puts("0");
			exit(0);
		}
	}
}

2.2 二分图判定方法的应用

NOIP2008 双栈排序
这道题的做法就是根据进哪个栈预处理出一个图,如果不是二分图就无解,如果是二分图就有解,然后根据题目要求输出就可以了

3.二分图匹配

3.1 增广路

先说题目意思吧,二分图匹配是我们要让二分图一部分的点尽可能的去匹配另一部分的点,当然一个点只能匹配一个点啦

这里我们要引入一个叫做增广路的东西,这也是网络流的基础
比如说对于这样的一个二分图
在这里插入图片描述
我们现在要进行匹配,那么我们先枚举左边的点,从第一个开始
匹配右边的第一个
在这里插入图片描述
当我们枚举第二个点的时候,我们发现,他已经不能和第一个匹配了,所以我们连向右边第三个点
在这里插入图片描述
然后我们枚举左边的第三个点,他已经不能和右边第三个匹配了,但是他没有别的出边了,怎么办呢,我们观察这条红色的路径
在这里插入图片描述
这条路径,从左3出发,经过未匹配边->匹配边->未匹配边->匹配边->未匹配边,我们发现,如果我们把这条路径上的匹配情况整体取反一下,匹配边变成未匹配边,未匹配边变成匹配边,就变成了
在这里插入图片描述
那么我们发现,这时候匹配数就增加了1!
像这样,经过未匹配边->匹配边->…->匹配边->未匹配边的一条路径,就叫做一条增广路

3.2 匈牙利算法

匈牙利算法正是基于增广路的一种解决二分图匹配的做法
我们发现,当我们找到一条增广路,我们把这条路径上的所有匹配关系取反之后,匹配数就+1,那么匈牙利算法就是不停的找增广路,一旦找到一条,那么就整体匹配关系取反,答案+1
那么实现也很简单,大概放下代码吧

bool dfs(int u){
   
   
    if(vis[u])return false;//vis表示这一次找增广路的时候有没有访问过这个点,如果一个点之前已经访问过了说明找不到增广路
    vis[u]=true;
    RepG(i,u){
   
   //枚举出边
        int v=e[i].to;
        if(!match[v]||dfs(match[v])){
   
   
        //match[v]表示v点之前匹配的点,如果v之前还没有一个点和他匹配,或者往他之前匹配的那个点去找增广路找到了
        //就把匹配关系在回溯的时候整体取反一下,让match[v]=u,然后返回true说明找到了一条增广路
            match[v]=u;
            return true;
        }
    }
    return false;//如果没找到,返回false
}

void hungary(){
   
   
    Rep(i,1,totx){
   
   
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;//如果找到了增广路,就说明这个点能匹配上,答案+1
    }
}

匈牙利算法的复杂度可以证明是 O ( n m ) O(nm) O(nm)的,因为每个点都要枚举一遍,最差情况下每条边都要经过一遍,但是这只是最差情况下复杂度,大家如果接触过网络流的话就知道网络流的复杂度是很难跑满的

3.3 网络流求二分图匹配

网络流我之前有讲过,大家可以看这里
用网络流跑二分图匹配就是建立一个超级源点和汇点,源点往左半部分每个点连一个容量为1的边,右半部分每个点往汇点连一个容量为1的点,然后每条边都相应的连上,容量均为1,就可以跑最大流了,最后的答案就是最大流量
那么问题来了,怎么判断最后匹配的情况呢?
因为用匈牙利的话我们可以直接用match看出匹配情况,但是网络流怎么看呢?
我们可以判断原图上的每一条边,他的反边是否有流量(因为这道题容量都是1,看正边容量是不是0也行),如果有,说明这两个点是匹配的
d i n i c dinic dinic求二分图匹配的复杂度最差可以证明是 O ( n n ) O(n\sqrt n) O(nn ),一样也是通常跑不到
而且一般出题人也不会看匈牙利吧
代码就不放了

3.4 二分图匹配的应用

应用就很多了,这也是二分图匹配最常考的了
最常见的就是两种题型吧,一个是题目里明确说了要匹配的,正常连边就可以
还有一个是二分图的一个转化模型,比如说放棋子,每行只能放一个,每列只能放一个这种的,那么我们可以把每一行当成左半部分的点,每一列当成右半部分的点,每个能放棋子的地方就把他的行向列连一条边就可以了,这样的题目也不少,比如说
P1263 宫廷守卫 上面的模型稍微变化一下就好了
[SCOI2015] 小凸玩矩阵 二分一下就好等等
然后还有一些其他的,比如说
[JSOI2016] 反质数序列判断质数,按奇偶性连边
这里就不一一列举了

4.二分图最小点覆盖

4.1 定义

二分图最小点覆盖的定义对于一个二分图,选择最少的点,让图中所有的边至少有一个端点属于这些点

4.2 二分图最小点覆盖定理

内容
二分图最小点覆盖定理:二分图最小点覆盖=二分图最大匹配数
证明
我们先构造出一个二分图的匹配情况
在这里插入图片描述
我们从左侧每一个没有被匹配的点出发(在这幅图是左2,5),走所有不完全的增广路,就是说构成是 未匹配边->匹配边->…->匹配边这样的路径,标记经过的点,这幅图中应该有两条,分别是
在这里插入图片描述
红色的和蓝色的这两条
然后我们看左半部分没有被访问过的(左3)和右半部分被访问过的(右2,4)
这就是我们二分图的一个最大独立集
为什么呢?

我们可以用反证法来证明
假设还有一条边没有被这几个点覆盖,那么显然他的左端点是一个匹配了的点
当这条边是一个匹配边时
如果这条边的右端点只有一条边,那么他的右端点不会访问到,所以没有一条不完全增广路会从右边过来,而左端点又不是不完全增广路的起点(因为已经匹配),所以他不会被覆盖,所以他的左端点属于左边没有被访问到的点,矛盾
如果这条边的右端点有大于一条边,那么他一定会属于一条不完全增广路,那么右端点一定属于右边别访问到的点,矛盾
当这条边不是一个匹配边时
他连向的点一定是右边被访问的,所以这条边也别覆盖,矛盾。
所以这些点一定可以覆盖所有的边

下面要证明这些点少一个一定不行,这个证明方法跟上面类似,这里就不再过多赘述了,大家可以下去自己证一下。

那么通过这种构造方法,就得到了一个二分图最小点覆盖。
那么为啥这个最小点覆盖是最大匹配数呢?
我们可以逆着增广路来想,每个右边被访问过的点一定对应一条匹配边,左边每个没有被访问过的点一定也对应一条匹配边(如果左边点没有被匹配他就是不完全增广路的起点了),所以我们得到结论

二 分 图 最 小 点 覆 盖 = 二 分 图 最 大 匹 配 数 \boxed{二分图最小点覆盖=二分图最大匹配数}

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值