[BOI2003]团伙
题目描述
给定 (n) 个人,他们之间有两个种关系,朋友与敌对。可以肯定的是:
- 与我的朋友是朋友的人是我的朋友
- 与我敌对的人有敌对关系的人是我的朋友
现在这 (n) 个人进行组团,两个人在一个团队内当且仅当他们是朋友。
求最多的团体数。
输入输出格式
输入格式
第一行一个整数 (n) 代表人数。
第二行一个整数 (m) 代表每个人之间的关系。
接下来 (m) 行每行一个字符 (opt) 与两个整数 (p,q)
- 如果 (opt) 为
F
代表 (p) 与 (q) 为朋友。 - 如果 (opt) 为
E
代表 (p) 与 (q) 为敌人。
输出格式
一行一个整数代表最多的团体数。
输入输出样例
输入样例 #1
6
4
E 1 4
F 3 5
F 4 6
E 1 2
输出样例 #1
3
说明
对于 (100\%) 的数据,(2 le n le 1000),(1 le m le 5000),(1 le p,q le n)。
分析
此题是一道很经典的题,与我之前写的一道题非常类似,戳这里看那道题的题解
此题和那道题的方法非常类似,是朋友就合并,是敌人就和敌人的敌人合并。
此题的思路异常简单,所以分析并没有那么多。但是平常思路如此简单的题我是不会写题解的,但是这道题为什么我写了呢?
因为 他是一道非常非常经典的题。
不多说废话,直接上代码。
代码
/*
* @Author: crab-in-the-northeast
* @Date: 2020-08-19 01:17:15
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-08-19 01:27:21
*/
#include <iostream>
#include <cstdio>
const int maxn = 1005;
int fa[maxn], enemy[maxn];
int find(int x) {
while (x != fa[x]) x = fa[x] = fa[fa[x]];
return x;
}
void unite(int x, int y) {
int fax = find(x);
int fay = find(y);
fa[fax] = fay;
return ;
}
int main() {
int n, m;
std :: scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
fa[i] = i;
for (int i = 1; i <= m; ++i) {
char op;
int p, q;
std :: cin >> op >> p >> q;//本来这里想用std :: scanf结果因为字符原因不行,只好用cin了(哭
if (op == 'F') unite(p, q);//是朋友就合并
else if (op == 'E') {
if (!enemy[q]) enemy[q] = p;//记录q的敌人p
else unite(p, enemy[q]);//将p和q的敌人合并
if (!enemy[p]) enemy[p] = q;//记录p的敌人q
else unite(q, enemy[p]);//将q和p的敌人合并
} else {
std :: printf("DBXXX AK IOI");//NEVER THIS WAY
}
}
int ans = 0;
for (int i = 1; i <= n; ++i)
if (fa[i] == i)
++ans;
std :: printf("%d
", ans);
return 0;
}