P1892 [BOI2003]团伙
一、理解与感悟
种类并查集的模板题。
相关资料:
https://zhuanlan.zhihu.com/p/97813717
相关试题:
https://www.cnblogs.com/littlehb/p/15111650.html
二、完整代码
#include <bits/stdc++.h>
using namespace std;
int n;//人数
int m;//关系数
char opt;//F: 代表 p 与 q 为朋友;E:代表 p 与 q 为敌人。
int p, q;//两个人员
int cnt;//最终的集合数量
//输出:一行一个整数代表最多的团体数
const int N = 1000 * 2 + 10;
//fa[i]表示i所属的集合,用fa[i+n]表示i所属集合的补集,实现的很巧妙,可以当成一个使用并查集的巧妙应用;
int fa[N]; //并查集数组,有时也写成 N << 1 ,从左到右,读作N左移1位,就是 2*N
//要深入理解这个递归并压缩的过程
int find(int x) {
if (fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
//加入家族集合中
void join(int c1, int c2) {
int f1 = find(c1), f2 = find(c2);
if (f1 != f2)fa[f1] = f2;
}
/**
测试用例:
6
4
E 1 4
F 3 5
F 4 6
E 1 2
答案:
3
*/
int main() {
//输入人数与关系数
cin >> n >> m;
//初始化并查集
for (int i = 1; i <= 2 * n; i++)fa[i] = i;
//输入关系
for (int i = 1; i <= m; i++) {
cin >> opt >> p >> q;
switch (opt) {
case 'E':
join(q + n, p);
join(p + n, q);
break;
case 'F':
join(p, q); //把p加入到q的家族中
break;
}
}
//找出最终的集合数量
for (int i = 1; i <= n; i++) if (fa[i] == i)cnt++;
//输出
cout << cnt << endl;
return 0;
}