在一個社區裏,每個人都有自己的小圈子,還可能同時屬於很多不同的朋友圈。我們認爲朋友的朋友都算在一個部落裏,於是要請你統計一下,在一個給定社區中,到底有多少個互不相交的部落?並且檢查任意兩個人是否屬於同一個部落。
輸入格式:
輸入在第一行給出一個正整數N(≤104),是已知小圈子的個數。隨後N行,每行按下列格式給出一個小圈子裏的人:
K P[1] P[2] ⋯ P[K]
其中K是小圈子裏的人數,P[i](i=1,⋯,K)是小圈子裏每個人的編號。這裏所有人的編號從1開始連續編號,最大編號不會超過104。
之後一行給出一個非負整數Q(≤104),是查詢次數。隨後Q行,每行給出一對被查詢的人的編號。
輸出格式:
首先在一行中輸出這個社區的總人數、以及互不相交的部落的個數。隨後對每一次查詢,如果他們屬於同一個部落,則在一行中輸出
Y
,否則輸出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
分析:
經典的並查集問題。
實現代碼:
#include<iostream> #include<map> #include<set> using namespace std; int p[10000]; void init() { for (int i = 0; i < 10000; i++) p[i] = i; } int find(int x) { while (p[x] != x) x = p[x]; return x; } void unite(int x, int y) { x = find(x); y = find(y); if (x != y) p[x] = y; } int main(void) { init(); int n, k, id1, id2; set<int> s; cin >> n; for (int i = 0; i < n; i++) { cin >> k >> id1; s.insert(id1); for (int j = 1; j < k; j++) { cin >> id2; unite(id1, id2); s.insert(id2); } } map<int, set<int>> m; for (set<int>::iterator it = s.begin(); it != s.end(); it++) { int head = find(*it); m[head].insert(*it); } cout << s.size() << " " << m.size() << endl; int q; cin >> q; for (int i = 0; i < q; i++) { cin >> id1 >> id2; if (m[find(id1)].find(id2) == m[find(id1)].end()) cout << "N"; else cout << "Y"; cout << endl; } }