在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入格式:
输入在第一行给出一个正整数
N
(
≤
1
0
4
)
N(≤10^4 )
N(≤104),是已知小圈子的个数。随后
N
N
N行,每行按下列格式给出一个小圈子里的人:
K , P [ 1 ] , P [ 2 ] ⋯ P [ K ] K ,P[1], P[2] ⋯ P[K] K,P[1],P[2]⋯P[K]
其中K是小圈子里的人数, P [ i ] ( i = 1 , ⋯ , K ) P[i](i=1,⋯,K) P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过 1 0 4 10^4 104 。
之后一行给出一个非负整数 Q ( ≤ 1 0 4 ) Q(≤10^4 ) Q(≤104),是查询次数。随后 Q Q Q行,每行给出一对被查询的人的编号。
输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出
Y
Y
Y,否则输出
N
N
N。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2
Y
N
对于本题中要求的求出人的个数,可以使用set来存人,这样就可以自动屏蔽掉重复的人,而题目之后要求求出不联系的部落的个数并且还要询问任意两个人是否是一个部落,这里可以把部落看成一个个集合,这个问题可以使用并查集来解决。
#include<iostream>
#include<set>
using namespace std;
const int N = 1e4 + 10;
int p[N]; //并查集存祖宗节点的数组
int find(int x) { //找到祖宗节点的find函数
if (p[x] != x)p[x] = find(p[x]);
return p[x];
}
int main() {
int n; cin >> n;
set<int>s; //用set来存人
for (int i = 1; i <= N; i++)p[i] = i;//一定要初始化并查集,i的祖宗节点初始化为i
for (int i = 1; i <= n; i++) { //读入
int k; cin >> k;
int b; cin >> b; //先读一个数
s.insert(b);
for (int j = 2; j <= k; j++) {
int a; cin >> a;
p[find(b)] = find(a); //把b的祖宗节点指向a的祖宗节点,合并两个集合
s.insert(a);
}
}
int num = 0;
for (int i = 1; i <= s.size(); i++) { //遍历所有人数
if (p[i] == i)num++; //如果第i个人的祖宗节点是他自己,那就说明有一个新的集合
}
cout << s.size() << " " << num << endl; //s.size()为总人数,num为没有联系的集合个数
int q; cin >> q;
while (q--) {
int a, b; cin >> a >> b;
if (find(a) == find(b))cout << "Y" << endl; //如果在一个集合中就输出Y
else cout << "N" << endl;
}
return 0;
}