团伙
时间限制(普通/Java): 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 125 测试通过 : 20
题目描述
在某城市里住着N个人,任何两个认识的人不是朋友就是敌人,而且满足:
1、 我朋友的朋友是我的朋友;
2、 我敌人的敌人是我的朋友;
所有是朋友的人组成一个团伙。告诉你关于这N个人的M条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?
输入
第一行包含一个整数N,第二行包含一个整数M,1<N<=1000,1<=M<=5000;
接下来M行描述M条信息,内容为以下两者之一:“F X Y”表示X与Y是朋友;“E X Y”表示X与Y是敌人。
输出
包含一个整数,即可能的最大团伙数。
样例输入
6
4
E 1 4
F 3 5
F 4 6
E 1 2
样例输出
3
题目来源 JSOI2010
题目链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1425
题目分析:本题和poj1703同一背景,但做法截然不同,这题貌似不好用偏移量来做,因为要求具体的团伙数,不一定只有两个,因此合并的时候要按逻辑判断,设一个e数组e[x] = y表示x和y是敌人,若F x y则直接合并,直接看代码注释,这里不好说
#include <cstdio>
int fa[1005], e[1005], n;
void UF_set()
{
for(int i = 0; i <= n; i++)
{
fa[i] = i;
e[i] = 0;
}
}
int Find(int x)
{
return x == fa[x] ? x : Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
{
fa[r1] = r2;
//合并时,若r2有敌人
if(e[r2] != 0)
{
//若r1也有敌人
if(e[r1] != 0)
//则它们的敌人是朋友
Union(e[r1], e[r2]);
else
//否则,r2的敌人同时也是r1的敌人
e[r1] = e[r2];
}
}
}
int main()
{
char s[2];
int m, x, y, cnt = 0;
scanf("%d %d", &n, &m);
UF_set();
for(int i = 0; i < m; i++)
{
scanf("%s %d %d", s, &x, &y);
if(s[0] == 'F')
Union(x, y);
else
{
//找到x的祖先,和x同一帮派
x = Find(x);
//若其祖先没有敌人,则将y当作其敌人,其实就是将y当作这个帮派的敌人
if(e[x] == 0)
e[x] = y;
//若其祖先有敌人,则敌人的敌人是朋友,将它的两个敌人合并
else
Union(e[x], y);
//对y的操作和对x的雷同
y = Find(y);
if(e[y] == 0)
e[y] = x;
else
Union(e[y], x);
}
}
for(int i = 1; i <= n; i++)
if(Find(i) == i)
cnt++;
printf("%d\n", cnt);
}