二分图的染色法判定

二分图的染色法判定


二分图的定义:如果一张无向图的 \(n\) 个顶点可以分为 \(A,B\) 两个不相交的集合,并且同一集合内的所有点之间没有边相连,记这张特征图为二分图

\(\implies\) 每一条边都是连接两个集合的边,所以从一个集合出发需要经过偶数条边才能走回原来的集合

推理:二分图不存在奇环(边数为奇数的环)

二分图的判定:染色法,用两种不同的颜色标记整张图,当一个节点被颜色 \(1\) 标记后,那么它相邻的节点会被标记颜色 \(2\) ,如果标记过程中,存在颜色冲突,那么图中存在奇环


int n,m;
vector<int> e[N];

cin>>n>>m;
for (int i=1;i<=m;i++) {
	int u,v;
	cin>>u>>v;
	e[u].push_back(v);
	e[v].push_back(u);
}

因为不考虑每条边的边权,所以之间利用 vector<int> e[N] 存图,e[u]=v 表示 \(u\) 点到 \(v\) 点存在一条边

然后 DFS 对每个点尝试染色

int color[NN];//0表示没有被染色

bool dfs(int u,int c){//走到u点应该染c表示的颜色
	color[u]=c;
	for (auto v:e[u]){//遍历u点的邻点
		if (!color[v]){//如果没有被染色
			if (dfs(v,3-c)){//走到v点,dfs染3-c表示的颜色,c=1,3-c=2 c=2,3-c=1
				return 1;//如果dfs递归后为1,向上回溯1表示存在奇环
			}
		}
		if (color[v]==c)//如果冲突,递归结束,返回1,表示存在负环
			return 1;
	}
	return 0;//0表示不存在奇环
}

对每个没有被染色的点进行一次 DFS ,直到整张图都被染色

bool f=0;//判断是否存在奇环
for (int i=1;i<=n;i++){
	if (!color[i]){//如果没有被染色,那么从这个点开始dfs
		if (dfs(i,1)){
			f=1;
			break;
		}
	}
}

例如洛谷P1330

题目要求的是找到最少的河蟹数量,使得每条边至少有一个端点被覆盖(河蟹占据),并且相邻的两个点不能同时有河蟹

这实际上等价于求图的一个顶点覆盖,且覆盖的顶点集合是一个独立集

所以需要记录每次 DFS 过程中两种颜色点的数量,取最小的累加答案

// Problem: P1330 封锁阳光大学
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1330
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
 
using namespace std;

int n,m;
vector<int> e[10010];
int color[10010];
int ans,cnt1,cnt2;

bool dfs(int u,int c){
	color[u]=c;
	if (c==1) cnt1++;
	else cnt2++;
	for (auto v:e[u]){
		if (!color[v]){
			if (dfs(v,3-c)){
				return 1;
			}
		}
		if (color[v]==c)
			return 1;
	}
	return 0;
}

int main()
{
	cin>>n>>m;
	for (int i=1;i<=m;i++) {
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	
	bool f=0;
	for (int i=1;i<=n;i++){
		if (!color[i]){
			cnt1=0,cnt2=0;
			if (dfs(i,1)){
				f=1;
				break;
			}
			ans+=min(cnt1,cnt2);
		}
	}
	if (f) cout<<"Impossible";
	else cout<<ans;
	return 0;
}
posted @ 2025-03-16 21:21  才瓯  阅读(40)  评论(0)    收藏  举报