今天花了時間在網上學了並查集。先上例題,解析在注釋裡。
題目: 親戚(Relations)
或許你並不知道,你的某個朋友是你的親戚。他可能是你的曾祖父的外公的女婿的外甥的表姐的孫子。如果能得到完整的家譜,判斷兩個人是否親戚應該是可行的,但如果兩個人的最近公用祖先與他們相隔好幾代,使得家譜十分龐大,那麼檢驗親戚關係實非人力所能及.在這種情況下,最好的幫手就是電腦。</
為了將問題簡化,你將得到一些親戚關係的資訊,如同Marry和Tom是親戚,Tom和B en是親戚,等等。從這些資訊中,你可以推出Marry和Ben是親戚。請寫一個程式,對於我們的關心的親戚關係的提問,以最快的速度給出答案。
參考輸入輸出格式 輸入由兩部分組成。
第一部分以N,M開始。N為問題涉及的人的個數(1 ≤ N ≤ 20000)。這些人的編號為1,2,3,…,N。下面有M行(1 ≤ M ≤ 1000000),每行有兩個數ai, bi,表示已知ai和bi是親戚.
第二部分以Q開始。以下Q行有Q個詢問(1 ≤ Q ≤ 1 000 000),每行為ci, di,表示詢問ci和di是否為親戚。
對於每個詢問ci, di,若ci和di為親戚,則輸出Yes,否則輸出No。
範例輸入與輸出
輸入relation.in
10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4
7 10
8 9
輸出relation.out
Yes
No
Yes
#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define maxn 100int father[maxn],rank[maxn];//father表示該節點的父親的序號,rank表示該節點的“輩分”。例如:在1->2->3->4中,4的輩分為3.int n;void makeset(){int i;for(i=1;i<=n;i++){father[i]=i;//由於沒有父親,所以標記父親是自己,有的也可標記為-1.rank[i]=0;//無兒女,所以輩分為0.}}int getfather(int v)//求出該節點的祖父,也就最上面的那個節點。{ if (father[v]==v) return v; else { father[v]=getfather(father[v]);/*實現了路徑壓縮:舉個例子:如果本來的節點之間關係是1->2->3->4,那麼1,2,3,4的祖父都是4.但是在這個遞迴回溯的時候,father[v]=getfather(father[v]);讓1,2,3,4的father都指向了4,變成了1->4,2->4,3->4,4->4.當尋找1的祖父時,只要尋找一次就能找到,而不是原來的3次, 這樣的結構讓尋找起來更加的快速,路徑壓縮的快捷也就體現出來。*/ return father[v]; }}void Union(int x,int y)//如果x,y不屬於一個集合,讓他們合并成一個集合,操作是讓x的祖父變成y的祖父。{ //注意這裡是預設讓x的祖父變成y的祖父,如果y的祖父的rank比x的祖父的rank大,那麼則讓y的祖父變成x的祖父。//void judge(int x ,int y) 將考慮這種情況。int fx,fy; fx=getfather(x); fy=getfather(y); if(fy!=fx) father[fx]=fy;}bool same(int x,int y)//判斷是否是同一個集合{ return getfather(x)==getfather(y);}void judge(int x ,int y) //在void Union(int x,int y)預設讓x的祖父變成y的祖父,這裡考慮如果y的rank比x的rank大,那麼則讓y的父親變成x。這樣做為了路徑壓縮。{//if (rank[fx]>rank[fy]) 則y的輩分+1.int fx,fy; fx = getfather(x); fy = getfather(y); if (rank[fx]>rank[fy]) father[fy] = fx; else { father[fx] = fy; if(rank[fx]==rank[fy]) ++rank[fy]; }}int main(){int m,i;int a,b;while(cin>>n>>m){makeset();for(i=1;i<=m;i++){cin>>a>>b;if(!same(a,b))//判斷是否為一個集合{Union(a,b);judge(a,b);//實現路徑壓縮 }}cin>>m;for(i=1;i<=m;i++){cin>>a>>b;if(same(a,b))cout<<"Yes"<<endl;elsecout<<"No"<<endl;}}return 0;}