Description
在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:
1. 我朋友的朋友是我的朋友;
2. 我敌人的敌人是我的朋友;
所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?
Input
第1行为n和m,N小于1000,M小于5000; 以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。
Output
一个整数,表示这n个人最多可能有几个团伙。
Sample Input
6
4
E 1 4
F 3 5
F 4 6
E 1 2
Sample Output
3
HINT
{1},{2,4,6},{3,5}
Source
题解
并查集真水。
如果只有第一个条件,那么这道题就非常水,可以说是裸题了。但是,第二个条件就比较麻烦了。为了解决这个问题,可以对每个人(记为x)构造一个“宿敌”x+n。如果读入的两个人x和y是朋友,就将x和y放入一个集合。如果读入的两个人x和y是敌人,就将x和y+n、x+n和y连起来(因为敌人的敌人是朋友)。最后枚举1~n,寻找他们属于多少个集合即可。
样例图:(这里用横线代表是朋友,用带双向箭头的横线代表是敌人)
处理后的样例图:(可以看出,画圈的点分别属于三个集合)
标程
#include <cstdio>
#include <algorithm>
const int maxn=1000;
int fa[maxn*2+10],a[maxn+10];
int n,m,i,j,x,y,ans;
char c;
int find(int x)
{
return fa[x]==0?x:find(fa[x]);
}
int merge(int x,int y)
{
x=find(x);
y=find(y);
if (x!=y)
{
fa[x]=y;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
getchar();
scanf("%c%d%d",&c,&x,&y);
if (c=='F')
{
merge(x,y);//将x和y合并
}
if (c=='E')
{
merge(x,y+n);//将x和y+n合并
merge(x+n,y);//将x+n和y合并
}
}
for (i=1;i<=n;i++)
{
a[i]=find(i);//寻找属于哪一个并查集
}
std::sort(a+1,a+n+1);
ans=1;
for (i=2;i<=n;i++)
{
if (a[i]!=a[i-1])
{
ans++;//计算属于多少个并查集
}
}
printf("%d\n",ans);
return 0;
}