赞助了大大的西瓜
题目连接
首先你要会并查集
这道题用到了一个有趣的思想:反集
就是在原数据的基础上乘2
也就是再作一个集合,多出来的n~~2*n作为辅助答案
#include<iostream>
using namespace std;
int a[2010];
int n, m;
int findd(int x) { // 查找模板
return x == a[x] ? x : a[x]=findd(a[x]);
}
void merge(int x, int y) { // 并查集模板
x = findd(x), y = findd(y);
if(x != y) a[x] = y;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= 2*n; ++i) // 2倍数据
a[i] = i;
int x, y;
char c;
for(int i = 0; i != m; ++i) {
cin >> c >> x >> y;
if(c == 'F') {
merge(x, y); // 普通合并
} else {
// 不能直接合并
merge(x+n, y); // 先用反集分别保存一下
merge(y+n, x);
//如果a和b是敌人,合并n+b和a,n+a和b
//如果c和a是敌人,合并n+c和a,n+a和c
//那么b和c就并在一起了
// 注意这里的合并祖先是 在 1~n
// 如果写成merge(x, y+n) 祖先就在n~2*n里面了
// 因为merge里面 a[x] = y
}
}
int ans = 0;
for(int i = 1; i <= n; ++i)
if(a[i] == i) ans++;
cout << ans << endl;
return 0;
}
第一次做这种题,感觉这反集思想蛮有趣的