[jzoj 4672] [Codeforces 662B] Graph Coloring {bfs/染色问题}

版权声明:~~~感谢支持! https://blog.csdn.net/qq_39897867/article/details/88847231

题目

Description

现在你有一张无向图包含n个节点m条边。最初,每一条边都是蓝色或者红色。每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。

Input

第一行包含两个数n,m(1<=n,m<=100000)分别代表节点数和边的数量
接下来m行描述边,第i行ui,vi,ci,代表ui有一条颜色为ci的边与vi相连(ci是B或者是R),B代表蓝色,R代表红色。数据保证没有自环的边。

Output

如果没有方案就输出-1。否则第一行输出k代表最小的步数


解题思路

总体思想是分别检查将边变为蓝色,或者红色,然后取最优方案即可。
每一个点最多改变一次,因为改变两次等于没有变化。因此我们要将点分为两
个集合 S 和 T,分别代表要改变的点和不需要改变的点。如果我们现在要将所有边变
为红色,假设 u 和 v 之间有一条红色的边。如果要维持这种颜色,u 和 v 要属于同一个
集合(S 或者 T)。另一方面,如果这条边是蓝色,那么 u 和 v 就必须在两个不同的集
合。
于是问题简化为了 0-1 图染色问题,我们可以通过 DFS 或者 BFS 解决。因为图
不一定连通,所以有一些细节要注意。


代码

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#define rep(i,x,y) for (register int i=x;i<=y;i++)
using namespace std; 
const int nm=100100; 
struct node{int y,z,next;}a[nm*2];
int tot,n,m,fa[nm],d[nm],ans=2147483647,cnt,head[nm]; 
queue<int> q; 
void add(int x,int y,int z){
	a[++tot]=(node){y,z,head[x]}; head[x]=tot;
	a[++tot]=(node){x,z,head[y]}; head[y]=tot;
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int bfs(int s,int la){
	while (!q.empty()) q.pop(); 
	q.push(s); d[s]=1; int ant=1,r=1;  
	while (!q.empty()) {
		int x=q.front(); q.pop(); 
		for (register int i=head[x];i;i=a[i].next){
			int y=a[i].y; 
			if (d[y]!=2){
				if (la==a[i].z&&d[x]!=d[y]||la!=a[i].z&&d[x]==d[y]) return -1; 
			} else {
				d[y]=(d[x]+la+a[i].z)%2; 
				if (d[y]==1) ant++; 
				q.push(y); r++; 
			}
		}
	}
	if (r-ant<ant) ant=r-ant; 
	return ant; 
}
int main(){
	scanf("%d%d",&n,&m); 
	int x,y; char c; 
	rep(i,1,n) fa[i]=i;
	rep(i,1,m) 
	 scanf("%d%d",&x,&y),cin>>c,fa[find(x)]=find(y),add(x,y,(c=='R')?1:0); 
	rep(i,0,1) {
		cnt=0; 
		rep(j,1,n) d[j]=2; 
		rep(j,1,n) if (fa[j]==j) {
			int g=bfs(j,i); 
			if (g==-1) {cnt=-1; break;}
			cnt+=g; 
		}
		if (cnt>-1&&cnt<ans) ans=cnt; 
	}
	if (ans==2147483647) printf("-1"); else printf("%d",ans); 
}

猜你喜欢

转载自blog.csdn.net/qq_39897867/article/details/88847231
今日推荐