L2-024 部落-middle-並查集-set-(超時原因)
阿新 • • 發佈:2020-11-19
在一個社群裡,每個人都有自己的小圈子,還可能同時屬於很多不同的朋友圈。我們認為朋友的朋友都算在一個部落裡,於是要請你統計一下,在一個給定社群中,到底有多少個互不相交的部落?並且檢查任意兩個人是否屬於同一個部落。
輸入格式:
輸入在第一行給出一個正整數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<set> #define MAXSIZE 10002 using namespace std; int N, K, pre[MAXSIZE] = { 0 }; set<int> s; int find(int x) { int root = x; while (pre[root] != root) { root = pre[root]; } /*路徑壓縮*/ /*x的根節點為root; : 每個節點直接連線根結點, 將x前面所有前導元素都連線到根節點上去*/ int i = x, j; while (i != root) { j = pre[i];/*儲存當前i的前導*/ pre[i] = root;/*當前i前導直接連線到根節點上去*/ i = j;/*i=開始儲存的i的前導*/ } return root; } void join(int a, int b) { if (find(a) != find(b)) pre[find(a)] = b; } int main() { scanf("%d", &N); int p, t; for (int i = 0; i < N; ++i) { scanf("%d %d", &K, &p); if (pre[p] == 0)/*當沒有初始化的時候進行初始化*/ pre[p] = p; s.insert(p); for (int j = 1; j < K; ++j) { scanf("%d", &t); if (pre[t] == 0)/*當沒有初始化的時候進行初始化*/ pre[t] = t; s.insert(t); join(p, t); } } /*利用set的erase 和 begin 函式 找到部落個數,即首領為自己的點的個數*/ int num_people = s.size(), num_group = 0; while ( s.begin() != s.end() ) { if (*s.begin() == find(*s.begin())) ++num_group; s.erase(s.begin()); } cout << num_people << " " << num_group << endl; //判斷是否在同一個部落裡 int Q, a, b; scanf("%d", &Q); for (int i = 0; i < Q; ++i) { scanf("%d %d", &a, &b); printf("%c\n", find(a) == find(b) ? 'Y' : 'N'); } return 0; }