先来说一下什么是二分图,对于一个图,我们将其顶点集分为两部分A和B,从而使得任意一条边的两个顶点一个在A中一个在B中,而不会出现一条边的两个顶点全部在A中或全部在B中这种情况。
先来说一个定理:一个图是二分图当且仅当这个图中不存在奇数环,也就是不存在一个环的顶点个数是奇数个。
如果利用这个定理来判定一个图是不是二分图的话那么我们就可以使用染色的方法来进行实现,就是每一条边的两个顶点的颜色一定是不相同的,我们按照这个原则来对图进行染色,如果染色成功那么这个图就是一个二分图,否则就不是一个二分图。
给出一道例题及其代码实现:
输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
const int N=2e5+10;
int h[N],e[N],ne[N],color[N],idx;
//color[i]代表第i个节点的颜色
void add(int x,int y)
{
e[idx]=y;
ne[idx]=h[x];
h[x]=idx++;
}
bool dfs(int x,int c)
{
color[x]=c;
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(color[j]!=-1)//j节点已经染过颜色
{
if(color[j]==c) return false;//一条边的两个顶点颜色相同,矛盾
}
else if(!dfs(j,c^1)) return false;//发现矛盾
}
return true;//所有节点都没有发现矛盾就返回真
}
int main()
{
int n,m;
cin>>n>>m;
memset(h,-1,sizeof h);
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
memset(color,-1,sizeof color);//初始颜色为-1
bool flag=true;
for(int i=1;i<=n;i++)
{
if(color[i]==-1)
{
if(!dfs(i,1))//将当前点染成1号颜色
{
flag=false;//出现奇数环就直接退出
break;
}
}
}
if(flag) puts("Yes");
else puts("No");
return 0;
}