題意:
如題,現在有一個並查集,你需要完成合並和查詢操作。
分析:
開始學習並查集。並查集有兩種方式優化:按秩合併、路徑壓縮。按秩合併中的秩指的是樹的深度,即總是將更小的樹連接至更大的樹上。而路徑壓縮是一種在執行“查找”時扁平化樹結構的方法。關鍵在於在路徑上的每個節點都可以直接連接到根上。
代碼(只按秩合併):
#include<bits/stdc++.h>
using namespace std;
int father[10010],R[10010];
//建立一個新的集合,每一個子節點就是一個數,本身就是他的根節點
void Make_Set(int x){
father[x] = x; //根節點
R[x] = 0; //秩大小
}
//通過遞歸向上查找根節點,回溯時改變當前節點的父節點,直接指向根節點。
int Find_Set(int x){
if(x != father[x])
father[x] = Find_Set(father[x]);
return father[x];
}
//兩個集合的合併算法
void Union(int x, int y){
int GrandX = Find_Set(x);
int GrandY = Find_Set(y);
if(GrandX == GrandY)
return;
if(R[GrandX] < R[GrandY])
father[GrandX] = GrandY;
else{
if(R[GrandX] == R[GrandY])
R[GrandX]++;
father[GrandY] = GrandX;
}
}
int main(){
int n,m,z,x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
Make_Set(i);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&z,&x,&y);
if(z==1){
Union(x,y);
}else{
if(Find_Set(x)==Find_Set(y))
printf("Y\n");
else
printf("N\n");
}
}
return 0;
}
代碼(再經過路徑壓縮優化):
#include<bits/stdc++.h>
using namespace std;
int father[10010],R[10010];
//建立一個新的集合,每一個子節點就是一個數,本身就是他的根節點
void Make_Set(int x){
father[x] = x; //根節點
R[x] = 0; //秩大小
}
//查找的同時進行路徑壓縮。
int Find_Set(int x){
while(x != father[x]){
father[x]=father[father[x]];
x=father[x];
}
return x;
}
//兩個集合的合併算法
void Union(int x, int y){
int GrandX = Find_Set(x);
int GrandY = Find_Set(y);
if(GrandX == GrandY)
return;
if(R[GrandX] < R[GrandY])
father[GrandX] = GrandY;
else{
if(R[GrandX] == R[GrandY])
R[GrandX]++;
father[GrandY] = GrandX;
}
}
int main(){
int n,m,z,x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
Make_Set(i);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&z,&x,&y);
if(z==1){
Union(x,y);
}else{
if(Find_Set(x)==Find_Set(y))
printf("Y\n");
else
printf("N\n");
}
}
return 0;
}