標籤:並查集 noip 路徑壓縮 資料結構
題目描述 Description
若某個家族人員過於龐大,要判斷兩個是否是親戚,確實還很不容易,現在給出某個親戚關係圖,求任意給出的兩個人是否具有親戚關係。 規定:x和y是親戚,y和z是親戚,那麼x和z也是親戚。如果x,y是親戚,那麼x的親戚都是y的親戚,y的親戚也都是x的親戚。
輸入描述 Input Description
第一行:三個整數n,m,p,(n<=5000,m<=5000,p<=5000),分別表示有n個人,m個親戚關係,詢問p對親戚關係。 以下m行:每行兩個數Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有親戚關係。 接下來p行:每行兩個數Pi,Pj,詢問Pi和Pj是否具有親戚關係。
輸出描述 Output Description
P行,每行一個’Yes’或’No’。表示第i個詢問的答案為“具有”或“不具有”親戚關係。
範例輸入 Sample Input
6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6
範例輸出 Sample Output
Yes
Yes
No
資料範圍及提示 Data Size & Hint
n<=5000,m<=5000,p<=5000
這裡我們以這道題來講並查集,引用一下百度百科的描述:在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合并,其間要反覆尋找一個元素在哪個集合中。這一類問題近幾年來反覆出現在資訊學的國際國內賽題中,其特點是看似並不複雜,但資料量極大,若用正常的資料結構來描述的話,往往在空間上過大,電腦無法承受;即使在空間上勉強通過,啟動並執行時間複雜度也極高,根本就不可能在比賽規定的已耗用時間(1~3秒)內計算出試題需要的結果,只能用並查集來描述。
這題我們把有親戚關係的人放入一個集合,然後根據資料給出的點,如果兩個點在一個集合,則說明兩人又親戚關係。
在建立這個親戚關係的集合時我們用到了圖的聯通分量的維護,對於給出親戚關係並且沒在同一集合的點加入一個集合,
注意在查詢時用到了路徑壓縮
#include<stdio.h>#include<string.h>#define N 5005int pa[N];int find(int x){return pa[x] == x ? x : find(pa[x]);}int main(){int n, m, p;scanf("%d%d%d", &n, &m, &p);int i, a, b;for (i = 0; i <= n; i++)pa[i] = i;for (i = 0; i < m; i++){scanf("%d%d", &a, &b);a = find(a);b = find(b);if (a != b)pa[a] = b;}for (i = 0; i < p; i++){scanf("%d%d", &a, &b);if (find(a) == find(b))printf("Yes\n");else printf("No\n");}return 0;}
實用資料結構---並查集