分析:这题和POJ 2492差不多,所以我用的是并查集,可以把题意理解为有很多人,要分成两个帮派,每个帮派至少有1个人,输入n,m分别代表n个人,和m对有冲突的人,有冲突的不能在一个帮派里,要尽可能的使第一个帮派的人多一些,如果存在输出第1,2个帮派的人数,否则输出Poor wyh 。如果输入n=0或n=1的话肯定不满足题意,用root[]数组记录每个人的老大是谁,opp[]记录每个人的对手是谁,child[]记录每个人手下有几个小弟,visit[]记录每个人有没有被访问过。初始化每个人都没有对手,如果a有对手,b没有,那么opp[b]=a,把b加入到a的对手的集合中,集合的根为老大,a没有对手,b有同理;a,b都有对手,就把a加入到b的对手的集合,b加入到a的对手的集合。最后取每两个对立的小帮派中人数较多的,和不与任何人对立的形成一个大帮派。
# include <stdio.h>
# define max(x,y) x>y?x:y
int root[100005],opp[100005],visit[100005],child[100005];
int Find(int x)
{
if(x==root[x])
return x;
root[x]=Find(root[x]);
return root[x];
}
void Union(int x,int y)
{
int fx=Find(x),fy=Find(y);
root[fx]=fy;
}
int main()
{
int i,a,b,n,m,t,flag,ans;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
if(n<=1)
{printf("Poor wyh\n");continue;}
for(i=1;i<=n;i++)
{
root[i]=i;
opp[i]=visit[i]=child[i]=0;
}
flag=ans=0;
while(m--)
{
scanf("%d%d",&a,&b);
if(flag==1)
continue;
if(Find(a)==Find(b))
flag=1;
else if(opp[a]==0&&opp[b]==0)
{
opp[a]=b;
opp[b]=a;
}
else if(opp[a]==0)
{
opp[a]=b;
Union(a,opp[b]);
}
else if(opp[b]==0)
{
opp[b]=a;
Union(b,opp[a]);
}
else
{
Union(a,opp[b]);
Union(b,opp[a]);
}
}
if(flag==1)
printf("Poor wyh\n");
else
{
for(i=1;i<=n;i++)
child[Find(i)]++;
for(i=1;i<=n;i++)
if(!visit[Find(i)])
{
visit[Find(i)]=1;
if(!opp[Find(i)])
ans++;
else
{
visit[Find(opp[Find(i)])]=1;
ans+=max(child[Find(i)],child[Find(opp[Find(i)])]);
}
}
if(ans!=n)
printf("%d %d\n",ans,n-ans);
else
printf("%d %d\n",n-1,1);
}
}
return 0;
}