1370: [Baltic2003]Gang团伙
Time Limit: 2 Sec
Memory Limit: 64 MB
Submit: 772
Solved: 424
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
[
Submit][
Status][
Discuss]
很简单的并查集, 因为有敌人或朋友两种种类, 自然而然的想到拆点.
如果a和b是朋友的话, 就把a和b分别的集合合并:
如果是敌人的话, 那么就把a 和 b + n, a + n 和 b分别的集合合并. 什么意思呢? 因为敌人的敌人是朋友, 所以我们对于某点a, 设一个镜像一般的点a+n, a+n所在的并查集就是a的敌人的并查集, 所以a 和 b + n合并, 满足敌人的敌人是朋友(b+n是b的敌人的集合). a + n 和 b合并同理. 最后处理一遍有多少个集合就可以了.
#include<stdio.h>
const int maxn = 2005;
char ch[1];
bool vis[maxn];
int fa[maxn], ans, n, m;
inline const int read(){
register int x = 0;
register char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
int find(int x) { return (fa[x] == x) ? x : fa[x] = find(fa[x]);}
int main(){
n = read(), m = read();
for(int i = 1; i <= 2 * n; ++i) fa[i] = i;
for(int i = 1; i <= m; ++i){
scanf("%s", ch);
int x = read(), y = read();
if(ch[0] == 'E') fa[find(x)] = find(y + n), fa[find(x + n)] = find(y);
else fa[find(x)] = find(y);
}
for(int i = 1; i <= n; ++i) vis[find(i)] = true;
for(int i = 1; i <= 2 * n; ++i) if(vis[i]) ans++;
printf("%d\n", ans);
}