目录
题目描述
众所周知,香港的黑社会组织猖獗,警方希望能摸清他们的内部构成情况,特派小生前往调查。经过长期的卧底,小生初步获得了一些资料:整个组织有n个人,任何两个认识的人不是朋友就是敌人,而且满足:①我朋友的朋友是我的朋友;②我敌人的敌人是我的朋友。所有是朋友的人组成一个团伙。现在,警方委派你协助调查,拥有关于这n个人的m条信息(即某两个人是朋友,或某两个人是敌人),请你计算出这个城市最多可能有多少个团伙。
数据范围:2≤N≤2000,1≤M≤5000。输入
第一行包含一个整数N,第二行包含一个整数M,接下来M行描述M条信息,内容为以下两者之一:“F x y”表示x与y是朋友;“E x y”表示x与y是敌人(1≤x≤y≤N)。
输出
包含一个整数,即可能的最大团伙数。
样例输入
6
4
E 1 4
F 3 5
F 4 6
E 1 2
样例输出
3
代码
#include<bits/stdc++.h>
using namespace std;
int set1[10001]; // 并查集数组
int rank1[10001]; // 秩数组
int data[10001];
int con[10001];
bool cmp(int a, int b)
{
return a > b;
}
void Make_Set(int i) // 初始化集合
{
set1[i] = i;
rank1[i] = 0;
}
int Find1(int i) // 查找集合代表元
{
if (set1[i] == i)
return set1[i];
return Find1(set1[i]);
}
void Union(int i, int j) // 合并集合
{
i = Find1(i);
j = Find1(j);
if (i == j)
return;
if (rank1[i] > rank1[j]) // 按秩合并
set1[j] = i;
else
{
if (rank1[i] == rank1[j])
rank1[j]++;
set1[i] = j;
}
}
int main()
{
int n, m, x, y;
char a;
int i, j;
scanf("%d%d", &n, &m); // 输入点数和操作数
for (i = 1; i <= n * 2; i++)
{
Make_Set(i); // 初始化n*2个集合
}
for (i = 1; i <= m; i++)
{
cin >> a;
scanf("%d%d", &x, &y);
if (a == 'F') // 朋友关系合并集合
Union(x, y);
if (a == 'E') // 敌人关系合并集合
{
Union(x, y + n);
Union(y, x + n);
}
}
int step, ans = 0;
for (i = 1; i <= n * 2; i++) // 查找每个点所在集合
con[i] = Find1(i);
sort(con, con + n + 1, cmp); // 降序排序
for (i = 1; i <= n; i++) // 统计不同集合个数
{
if (con[i] != con[i - 1])
ans++;
}
printf("%d", ans); // 输出不同集合总数
}