[ 图 论 ]二分图判定及其匹配(基础+提高)

在解决判定和匹配任务之前,我想我们应该先了解什么是二分图

定义

二分图,又称二部图,英文名叫 Bipartite graph。

二分图是什么?节点由两个集合组成,且两个集合内部没有边的图。

换言之,存在一种方案,将节点划分成满足以上性质的两个集合。 − ( O I   W i k i ) -(OI\ Wiki) (OI Wiki)

那么首先我们先看一个一般的图

在这里插入图片描述

上图用了 6 6 6个点, 6 6 6条边。这样看起来没什么特别的对吧,我们将他做一下调整。

在这里插入图片描述

此图和上边的是等价的,但是我们将他们分成了两个集合 A , B A,B A,B,并且每个集合内部都没有边相连,这种图就是二分图。
了解了什么是二分图,我想我们可以开始我们要讲的判定了,现在你可以动手画一画,是不是所有的图都是二分图呢?显然这是不可能的,但这其中又有什么关系吗?比如现在我给出这样一个图👇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wc0MY84X-1658765797920)(C:\Users\Zgy66\AppData\Roaming\Typora\typora-user-images\image-20220725205755731.png)]

你能将他分成二分图吗?

在这里插入图片描述

当我们做这件事的时候,会发现无论怎么分,点 5 5 5必然会和 0 0 0 1 1 1在一个集合中,为什么?因为图中存在奇数环,这时候我们得出了第一个结论: 当图中有奇数环时,他一定不是二分图 , 反之没有奇数环的图一定是二分图 当图中有奇数环时,他一定不是二分图,反之没有奇数环的图一定是二分图 当图中有奇数环时,他一定不是二分图,反之没有奇数环的图一定是二分图

我们多举一个例子:

在这里插入图片描述

图中存在长度为 4 和 8 4和8 48的环,我们现在将他变成二分图
在这里插入图片描述

这是非常容易办到的(

接下来我们介绍如何去判定一个图是不是二分图。我这里给出的是一个常用的算法 染色法判断二分图 染色法判断二分图 染色法判断二分图

原理:我们可以将两个集合中的点给一个颜色,例如: A A A集合中的点我们都染成红色 B B B集合中的点我们都染成黑色,我们开一个 c o l o r [   ] color[\ ] color[ ]数组来记录每个点的颜色,起始,我们遍历每个点,如果没有被染色,我们就将他染成红色,然后将与他直接相连的点全部染成黑色,同理当我们将这个点染成黑色后,我们就要将与他直接相连的所有点染成红色,在这期间如果染色失败,那么就不是二分图,什么时候会出现染色失败呢?当我们染完一个点后,在染他的所有相邻的点的时候发现有一个点的颜色和他相同,也就是下面图中的情况.

在这里插入图片描述

1 1 1号点发现他的相邻点 0 0 0号点也是红色,那么这样就不行了对吧,就算我们把 1 1 1号点染成黑色,那么也会发现他的相邻点 5 5 5也是黑色,这时候就只能宣布:染色失败,图不是二分图

例题:染色法判定二分图

给定一个 n n n 个点 m m m 条边的无向图,图中可能存在重边和自环。

请你判断这个图是否是二分图。

输入格式

第一行包含两个整数 n n n m m m

接下来 m m m 行,每行包含两个整数 u u u v v v,表示点 u u u 和点 v v v 之间存在一条边。

输出格式

如果给定图是二分图,则输出 Y e s Yes Yes,否则输出 N o No No

数据范围

1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^5 1n,m105

输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes

这个题是染色算法的板子题,下面给出完整代码:

#include <bits/stdc++.h>
using namespace std;
//------邻接表存边
const int N=1e5+10,M=2*N;
int h[N],e[M],ne[M],idx;
int color[N];
void add(int a,int b)
{
   
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
//-------
//-------染色法判断二分图
bool dfs(int u,int c)
{
   
	color[u]=c;
	for(int i=h[u];i!=-1;i=ne[i])
	{
   
		int j=e[i];
		if(!color[j])//相邻点没有颜色,就染成不同的颜色
		{
   
			if(!dfs(j,3-c))return false;
		}else if(color[j]==color[u])return false;//相邻点与本身的颜色相同
	}
	return true;//将相邻点全部染色成功,只能说明这个点与他的相邻点没有产生矛盾
}
//--------
int main()
{
   
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	//----读入无向边
	memset(h,-1,sizeof h);
	int n,m;cin>>n>>m;
	while(m--)
	{
   
		int a,b;cin>>a>>b;
		add(a,b);add(b,a);
	}
	//-----
	bool f=true;
	for(int i=1;i<=n;i++)//开始染色
	{
   
		if(!color[i])
		{
   
			if(!dfs(i,1))f=false;//如果有一个点染色失败,就宣布失败
		}
	}
	if(f)cout<<"Yes";else cout<<"No";
	return 0;
}

到这里,我相信你已经对如何判定一个图是不是二分图有所了解了,那么这是远远不够的,因为二分博大精深(

我们将学习下一个知识点:二分图的最大匹配

这里我们不引入所谓的增广路概念,他对我来说比较抽象 h h hh hh,所以我们直接用白话的意思翻译一下,什么是最大匹配

查看源图像

转载知乎@青烟

他的最大匹配数就是 3 3 3,因为有三对点完成了匹配,分别是: { x 1 , y 4 } , { x 2 , y 2 } , { x 3 , y 3 } \{x_1,y_4\},\{x_2,y_2\},\{x_3,y_3\} { x1,y4},{ x2,y2},{ x3,y3}

所以最大匹配数就是一个二分图中,从两个集合中各拿出一个点,组成一对的最大对数。

了解了概念,我们如何求呢?这里给大家介绍一种算法:匈牙利算法

我们用一个例题来说明:二分图的最大匹配

给定一个二分图,其中左半部包含 n 1 n_1 n1 个点(编号 1 ∼ n 1 1∼n_1

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值