二分图定义:
简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。
二分图是这样一个图:有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接。
判定方法——染色法:
开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,dfs可以搞定!
代码:
无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数,则不存在奇环。
前提是:连通图
代码:
HDU3478 HDU3478题解
二分图是这样一个图:有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接。
判定方法——染色法:
开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,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题解