二分图的定义类似于集合,图中的每一条边都由两个点链接,我们可以把图的所有点分布在两侧,然后进行连接,如果出现某个点即在左边又在右边,那我们可以发现这个图肯定是构不成两个集合的;
具体一点是:二分图中没有奇数环;也就是没有奇数个点构成的环。
例如:
就像这张图,我们把左集合定命名为1,右集合命名为2,当我们一个一个遍历我们的点的的时候,我们把它打上标记(也就是染色),这个时候我们发现2这个点第一遍历的时候是2,但是结束的时候,我们的6是2,理论上来说。与6连接的2这个点应该是1,但事实上却不是如此;这个时候我们说这个图不是一个二分图;
偶数环大家自己画一下应该就能发现是符合条件的;
那么我们如何查找奇数环呢?我们使用的就是染色法;
具体使用dfs遍历所有点,判断每一个点的其他出边是否有与它一样的,一样就要返回错误,否则遍历完后没有错误,就返回正确;
具体代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000010;
int h[N],e[N*2],ne[N*2],idx=0;
int st[N];
int n,m;
int add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int he,int k)
{
st[he]=k;//先赋值
for(int i=h[he];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j]) //如果这个点没有被遍历过,就加入
{
if(!dfs(j,3-k)) //进行dfs
{
return false;//如果返回的是false,那么就是错误的,仍然返回false
}
}
else if(st[j]==k) return false;//发现他的出边有与他一样的值,说明出现奇数环
}
return true;
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
bool flag=1;
for(int i=1;i<=n;i++)
{
if(!st[i])
{
if(!dfs(i,1))
{
flag=false;//标记错误
break;
}
}
}
if(flag)
cout<<"Yes";
else
cout<<"No";
}
/*
3 3 1 2 2 3 1 3
4 4 1 2 2 3 3 4 2 4
*/