CF228E 题解

CF228E 题解

题目简述

给定一个 \(n\) 个点,\(m\) 条边的无向图,每条边都为 \(0\)\(1\),可以进行若干次操作,与此点相连的所有点权值取反,求一种方案使得所有边都变为 \(1\)

前置知识

  • 二分图
  • 二分图染色

思路简述

首先明白一点:对于同一条边,操作偶数次是没有必要的!因为最终会回到初始状态。

对于任意一条边 \(i\),有:

\(v_i = 0\),则状态为 \((x_i,y_i)=(0,1)\)\((x_i,y_i)=(1,0)\)

\(v_i=1\),则状态为 \((x_i,y_i)= (0,0)\)\((x_i,y_i)=(1,1)\)

然后我们就可以想到思路了。

用一个 color 数组来存储某个点 \(x\) 是没被染色(color[x]=-1),还是染为黑或白色(color[x] 等于 \(0\)\(1\))。

如果遇到某一条边,两个顶点颜色一样,则输出 Impossible,无解。

否则统计某种颜色的顶点个数,再依次输出即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=105,M=N*(N-1)/2;
int n,m,color[N],u,v,op,cnt_ans;
struct E{
	int from,to,pre,co;
}e[M<<1];
int head[N],cnt_e;
void add(int from,int to,int co)
{
	e[++cnt_e].from=from;
	e[cnt_e].to=to;
	e[cnt_e].pre=head[from];
	e[cnt_e].co=co;
	head[from]=cnt_e;
	return;
}
void dfs(int u,int co)
{
	color[u]=co;
	for(int i=head[u];i;i=e[i].pre)
	{
		int v=e[i].to,col=e[i].co;
		if(!col)
		{
			if(color[v]==-1)
				dfs(v,co^1);
			else
			{
				if(color[v]==color[u])
				{
					printf("Impossible\n");
					exit(0);
				}
			}
		}
		else
		{
			if(color[v]==-1)
				dfs(v,co);
			else
				if(color[u]!=color[v])
					printf("Impossible\n"),exit(0); 
		}
	}
	return;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		color[i]=-1;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&op);
		add(u,v,op);
		add(v,u,op);
	}
	for(int i=1;i<=n;i++)
		if(color[i]==-1)
			dfs(i,0);
	for(int i=1;i<=n;i++)
		if(!color[i])
			++cnt_ans;
	printf("%d\n",cnt_ans);
	for(int i=1;i<=n;i++)
		if(!color[i])
			printf("%d ",i);
	puts("");
	return 0;
}
posted @ 2024-08-05 21:40  Atserckcn  阅读(22)  评论(0)    收藏  举报