染色法
- 将所有点分成两个集合,使得所有边只出现在集合之间,就是二分图
- 二分图:一定不含有奇数环,可能包含长度为偶数的环, 不一定是连通图
-
dfs(起点)
-
dfs (u,c)函数:
- 对当前点u进行染色,染成c色
- 遍历u的所有临边,对于每个临边:
- 如果被染过色且染的还是c,返回false
- 如果没有被染过:
- 尝试对这个点使用c之外的另一种颜色染色,如果染色失败,返回false
- 返回染色成功。
#include
#include
using namespace std;const int N=100010,M=200010;
int n,m;
int h[N],e[M],ne[M],idx;
int color[N];void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}//从u起点开始,进行二染色,返回是否染色成功
bool dfs(int u,int c)
{
// 给当前点u染色
color[u]=c;// 遍历y的所有临边。 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%d",&n,&m);memset(h,-1,sizeof h); while(m--) { int a,b; scanf("%d%d",&a,&b); add(a,b),add(b,a); } bool flag=true; // 枚举所有的点 for(int i=1;i<=n;i++) { // 如果这个点没有被染过色 if(!color[i]) { //这里用1或者2都是无所谓的, // 一次dfs会给一个联通块进行全部染色 if(!dfs(i,1)) { flag=false; break; } } } if(flag) puts("Yes"); else puts("No"); return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
int e[M], ne[M], h[N], idx;
int n, m;
// st为0表示没染色,为1表示染1,为2表示染2
int st[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
bool bfs(int u){
int hh = 0, tt = 0;
int q[N];
q[0] = u;
st[u] = 1;
while(hh <= tt){
auto t = q[hh ++];
for (int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(!st[j])
{
st[j] = 3 - st[t];
q[++ tt] = j;
}
else if(st[j] == st[t]) return false;
}
}
return true;
}
int main(){
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a); // 无向图
}
int flag = true;
for(int i = 1; i <= n; i ++) {
if (!st[i]){
if(!bfs(i)){
flag = false;
break;
}
}
}
if (flag) puts("Yes");
else puts("No");
return 0;
}