有 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;
}