二分图定义:
如果一张无向图的 N 个节点可以分成 A,B 两个不相交的非空集合,并且同-集合内的点之间没有边相连,那么称该无向图为二分图。
定理:二分图不存在奇环(长度为奇数的环),因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合。
染色法
我们可以使用染色法来判定二分图。即尝试用两种颜色标记图中的节点,当一个点被标记后,所有与它相邻的节点应该标记与它相反的颜色,若标记过程产生冲突,则说明图中存在奇环。可以用 DFS 或 BFS 来实现。
例题(1):活动 - AcWing
题目:
给定一个 n 个点 m
条边的无向图,图中可能存在重边和自环。
请你判断这个图是否是二分图。
输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 u 和 v,表示点 u 和点 v之间存在一条边。
输出格式
如果给定图是二分图,则输出
Yes
,否则输出No
。
数据范围
1≤n,m≤10^5
输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e5 + 10,M = 2e5 + 10;
int n,m;
int h[N],e[M],ne[M],idx;
int color[N];
bool st[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] == c)
return false;
}
return true;
}
int main(){
cin >> n >> m;
memset(h,-1,sizeof h);
while(m --){
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
bool flag = true;
for(int i = 1;i <= n;i ++){
if(!color[i]){
if(!dfs(i,1)){
flag = false;
break;
}
}
}
if(flag) puts("Yes");
else puts("No");
return 0;
}
例题(2):695. 劣马 - AcWing题库
题目:
作为邪恶联盟的领导者,劣马有很多问题要处理。
联盟内有很多人关系恶劣甚至相互仇视,以至于劣马决定将联盟分成两个部门,以便将相互仇视的成员全部分开。
作为罪恶的领袖,劣马不会花费他宝贵的时间来作这项工作。
所以,他将这个任务交给了你。
输入格式
第一行包含整数 T,表示共有 T组测试数据。
每组数据第一行包含整数 M,表示共有 M对相互仇视的关系。
接下来 M行,每行包含两个用空格隔开的字符串,表示一对相互仇视的人员名单。
输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为
Case #x: y
,其中 x 是组别编号(从 1 开始),如果能将所有相互仇视的成员全部分开,则 y 是Yes
,否则 y 是No
。
数据范围
1≤T≤100,1≤M≤100
人员名字用字母和下划线构成,且区分大小写。在一组数据中,同一对仇视人员不会出现多次。
每对仇视关系涉及的二人一定不是同一个人。
输入样例:
2
1
Dead_Bowie Fake_Thomas_Jefferson
3
Dead_Bowie Fake_Thomas_Jefferson
Fake_Thomas_Jefferson Fury_Leika
Fury_Leika Dead_Bowie
输出样例:
Case #1: Yes
Case #2: No
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e5 + 10;
int t;
int color[N];
int e[N],ne[N],h[N],iii;
void add(int a,int b){
e[iii] = b,ne[iii] = h[a],h[a] = iii ++;
}
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] == c)
return false;
}
return true;
}
int main(){
scanf("%d",&t);
int num = 0;
while(t --){
num ++;
int n;
memset(color,0,sizeof color);
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
memset(h,-1,sizeof h);
scanf("%d",&n);
map<string,int> a;
int index = 0;
iii = 0;
for(int i = 0;i < n;i ++){
string x,y;
cin >> x >> y;
if(!a.count(x))
a[x] = index ++;
if(!a.count(y))
a[y] = index ++;
add(a[x],a[y]);
}
bool flag = true;
for(int i = 0;i < index;i ++){
if(!color[i]){
if(!dfs(i,1)){
flag = false;
break;
}
}
}
if(flag) printf("Case #%d: Yes\n",num);
else printf("Case #%d: No\n",num);
}
return 0;
}