P1892 [BOI2003]团伙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
现在有 nn 个人,他们之间有两种关系:朋友和敌人。我们知道:
- 一个人的朋友的朋友是朋友
- 一个人的敌人的敌人是朋友
现在要对这些人进行组团。两个人在一个团体内当且仅当这两个人是朋友。请求出这些人中最多可能有的团体数。
思路:
a和b是敌人 -> 合并 (a+n) 和 b ,合并 (b+n) 和 a;
a和c是敌人 -> 合并 (a+n) 和 c ,合并 (c+n) 和 a;
这样b和c就到了一个集合,而n到2n的部分称为反集
#include <algorithm>
#include <cstring>
#include <iostream>
#define dbg(x) cout << #x << '=' << x << endl
#define FA ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define INF 0x3f3f3f3f
using namespace std;
const int N = 1e6 + 10, M = 1e3 + 10, mod = 1e9 + 7;
const double eps = 1e-8;
typedef long long LL;
typedef pair<int, int> PII;
int p[N];
int find(int x) {
if (x != p[x]) {
return p[x] = find(p[x]);
}
return p[x];
}
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n * 2; i++) {
p[i] = i;
}
while (m--) {
char op;
int a, b;
cin >> op >> a >> b;
if (op == 'F') {
a = find(a), b = find(b);
if (a != b) {
p[b] = a;
}
} else {//反集合并
int aa = find(a), bb = find(b);
int c = find(a + n), d = find(b + n);
if (aa != d) p[d] = aa;
if (bb != c) p[c] = bb;
}
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (p[i] == i) cnt++;
}
cout << cnt;
}
int main() {
int T = 1;
// FA;
while (T--) {
solve();
}
return 0;
}