CF662B Graph Coloring

一、题目

点此看题

二、解法

刚开始一看可能没有什么思路,但是这个问题很像染色,先枚举最终染上的颜色,如果确定了一个点是否能够翻转,那么与其相连的点也能确定。

所以考虑对于每一个连通块,把他的第一个点设置成翻转,就可能拿到翻转点和不翻转点的个数,如果把第一个点设置成不翻转,那么所有点的翻转状态都会反过来,所以贪心地把这两者取 min \min 即可。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define inf 1e9
const int M = 100005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,fl,col,ans=inf,tot,t0,t1,f[M],vis[M];char s[5];
struct edge
{
	int v,c,next;
}e[2*M];
vector<int> v,v0,v1,v3;
void dfs(int u,int c)
{
	vis[u]=c;
	if(c==0) t0++,v0.push_back(u);
	else t1++,v1.push_back(u);
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v,w=e[i].c;
		if(vis[v]==-1)
			dfs(v,c^w^col);
		else if(vis[u]^vis[v]^w!=col)
		{
			fl=1;
			return ;
		}
	}
}
signed main()
{
	n=read();m=read();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();scanf("%s",s);
		e[++tot]=edge{v,s[0]=='R',f[u]},f[u]=tot;
		e[++tot]=edge{u,s[0]=='R',f[v]},f[v]=tot;
	}
	for(col=0;col<=1;col++)
	{
		int tmp=0;fl=0;
		v3.clear();
		memset(vis,-1,sizeof vis);
		for(int i=1;i<=n;i++)
			if(vis[i]==-1)
			{
				v0.clear();v1.clear();
				t0=t1=0;
				dfs(i,1);
				if(fl) break;
				tmp+=min(t0,t1);
				if(t0<t1)
				{
					for(int i=0;i<v0.size();i++)
						v3.push_back(v0[i]);
				}
				else
				{
					for(int i=0;i<v1.size();i++)
						v3.push_back(v1[i]);
				}
			}
		if(fl) continue;
		if(ans>tmp)
		{
			ans=tmp;
			v=v3;
		}
	}
	if(ans==inf) puts("-1");
	else
	{
		printf("%d\n",ans);
		for(int i=0;i<v.size();i++)
			printf("%d ",v[i]);
		puts("");
	}
}

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/107603595