洛谷 P1892 [BOI2003]团伙(并查集)

嗯...

 

题目链接:https://www.luogu.org/problemnew/show/P1892

 

通过读题可以很清楚的发现这是一个并查集的题,并且要有两个集合:

若他们p和q是朋友,则存入第一个集合;若他们是敌人,则存入第二个集合——即反集(很模糊的一个东西

因为最多只有n个数,所以我们将f数组一分为二,f [1] ~ f [n] 为第一个集合, f [n+1] ~ f [n + n] 为反集,然后根据题意进行并查集的基本操作即可...

本题细节:

(1) 注意读题,最后要求的一共有多少个团伙(即我们合并后一共有多少个父亲), 我们只需要从1 for 到 n,如果f [i] == i,ans++即可。

(2) 注意我们在f 数组中存了两个集合,会用到2 * n,所以在初始化f 数组的时候需要从1 for 到 2 * n。

(3) c,p,q的读入只能使用cin, scanf会爆掉。

(4) 第一个集合(p和q为朋友)直接合并即可,而反集的合并需要两次合并。(只能这么理解吧...详见代码

(5) 注意反集时find函数中的参数,而不是在find函数外再加n。

 

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 int f[10005], ans;
 8 int n, m, p, q;
 9 char c;
10 
11 inline int find(int x){
12     if(f[x] != x)
13         f[x] = find(f[x]);
14     return f[x];
15 }
16 
17 int main(){
18     scanf("%d%d", &n, &m);
19     for(int i = 1; i <= n * 2; i++)//注意两倍 
20         f[i] = i;
21     for(int i = 1; i <= m; i++){
22         cin >> c >> p >> q;
23         if(c == 'F'){
24             f[find(p)] = find(q);//是朋友直接合并 
25         }
26         if(c == 'E'){
27             f[find(p + n)] = find(q);//反集合并两次,注意在find函数中的参数 
28             f[find(q + n)] = find(p);
29         }
30     }
31     for(int i = 1; i <= n; i++){
32         if(f[i] == i) ans++;//自己为根节点的个数,即集团个数 
33     }
34     printf("%d", ans);
35     return 0;
36 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/10883425.html