图论之二分图的判定

二分图定义:
简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。
二分图是这样一个图:有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接。

判定方法——染色法:
       开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,dfs可以搞定!
 代码:
 
#include<stdio.h> 
#include<string.h>
#include<vector>
#define MAX_V 1000
using namespace std;
int col[MAX_V];
vector<int>G[MAX_V];
int Dfs(int v,int color){//点V染成color色 
	col[v]=color;
	for(int i=0;i<G[v].size();i++){  //遍历所有与v相邻的点 
		int u=G[v][i];
		//如果相邻顶点已经被染成同色了,说明不是二分图 
		if(col[u]==color) return 0;
		//如果相邻顶点没有被染色,染成-color,看相邻顶点是否满足要求
		if(!col[u]&&!Dfs(u,-color)) return 0;
	}
	return 1;
}
void work(int n){
	memset(col,0,sizeof(col));
	int flag=0;//判断是否为二分图 
	int cnt=0;//记录联通块 
	for(int i=1;i<=n;i++){
		if(!col[i]){
		    cnt++;
			if(!Dfs(i,1)){
				flag=1;
				break;
			}
		}
	}
	if(flag) printf("No\n");
	else if(cnt>1) printf("Not connecting\n");
	else printf("Yes\n");
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	   G[i].clear();
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a);
	}
	work(n);
	return 0;
}
判断方法——并查集
      无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数,则不存在奇环。
  前提是:连通图
代码:
#include<stdio.h>
#include<string.h>
using namespace std;
const int N = 1e5+5;
int pre[N*2];
void init(int n){
	for(int i=1;i<=n*2;i++)
	   pre[i]=i;
}
int Find(int x){ //非递归查找x的父节点 
	int r=x;
	while(r!=pre[r]){
		r=pre[r];
	}
	int i=x,j;
	while(i!=r){
		j=pre[i];
		pre[i]=r;
		i=j;
	}
	return r;
}
/*
int Find(int x){//递归查找x的父节点
	return x==pre[x]?x:pre[x]=Find(pre[x]);
}
*/
void mix(int a,int b){
	int fa=Find(a),fb=Find(b);
	if(fa!=fb) pre[fb]=fa;
}
void work(int n){
	int flag=0;
	for(int i=1;i<=n;i++){
		//如果i和i+n属于同一个集合,则说明有奇环存在 
		if(Find(i)==Find(i+n)){
			flag=1;
			break;
		}
	}
	if(flag) printf("No\n");
	else printf("Yes\n");
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	init(n);
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		//如果有连边,就将a与b+n归为一个集合
		//b与a+n归为一个集合 
		mix(a,b+n);
		mix(b,a+n);
	}
	work(n);
	return 0;
}
相关好题:
HDU3478  HDU3478题解


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值