CF216B 题解

题目大意

n n n 个学生,他们中有 m m m 对人互相仇视,且每个人至多仇视 2 2 2 个人。给出这 m m m 对互相仇视的人,需要将所有学生分成人数相等的两组(来打球),且互相仇视的人不能在一组。但为了满足要求,有些人可能不得不放弃参加分组(坐板凳)。

输出不能参加分组的最少人数。

题目思路

题目给出每个人至多仇视 2 2 2个人的性质,所以这个图只可能由环、链或点组成。

每个环、链、点之间独立,所以我们单独计算他们的贡献。

如果当前环的长度为偶数,那么这个环就不会做出贡献;

反之,总有一个人是不能放的。

如果当前链的长度为偶数,那么这条链同样不会做出贡献;

但是,当链的长度为奇数时,我们可以将空出的那个人当成一个点去看待。

最后,我们将所有单独点的个数统计出来,如果为奇数就会做出贡献,反之则不会。

具体实现参考代码。

#include
using namespace std;
int n,m,fa[1000+10],p[1000+10],siz[1000+10],vis[1000+10],tot=0,ans=0;
set<int> s;
int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')	
		s=s*10+(ch-'0'),ch=getchar();
	return s*w;
}
int fd(int x)
{
	if(fa[x]==x)
		return x;
	else
		return fa[x]=fd(fa[x]);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;++i)
		fa[i]=i,siz[i]=1;
	for(int i=1;i<=m;++i)	
	{
		int u=read(),v=read();
		int x=fd(u),y=fd(v);
		if(x!=y)
			fa[y]=x,siz[x]+=siz[y];
		else
			p[x]=1;
		s.insert(x);
		s.insert(y);
	}
	for(int i=1;i<=n;++i)
	{
		if(s.find(i)!=s.end())
		{
			int u=fd(i);
			if(vis[u])
				continue;
			vis[u]=1;
			if(p[u])
				ans+=siz[u]&1;
			else
				tot+=siz[u]&1;
		}
		else
			tot++;
	}	
	ans+=tot&1;
	printf("%d",ans);
	return 0;
}

你可能感兴趣的:(题解,算法)