PAT甲級1013並查集筆記(路徑壓縮)
阿新 • • 發佈:2021-01-17
PAT甲級1013(並查集)
這篇文章主要記錄一下並查集的路徑壓縮方法,在資料量不大時,可以不使用路徑壓縮,但當資料量較大時,不使用路徑壓縮則會超時,就比如這個1013題的最後一個測試點。
先看一下並查集中的find_root函式,也就是找根節點的函式:
int find_root(int parent[],int x){
//不進行路徑壓縮
while(parent[x]!=-1){
x = parent[x];
}
return x;
}
可以看到,不進行路徑壓縮的話,就只是找到某一個x的根節點就行了,但是這樣的話,找每一個x的根節點,都要一直往上找父節點,直到找到根節點為-1的節點為止,資料量小時影響不大,但資料量大的時會非常浪費時間,因為每找一個都要進行很多次的while迴圈。
int find_root(int parent[],int x){
int a = x;
while(parent[x]!=-1){
x = parent[x];
}
//路徑壓縮
while(a!=x){
int tmp = parent[a];
parent[a] = x;
a = tmp;
}
return x;
}
這個函式的返回值還是和原來一樣,只與x本身有關,為了路徑壓縮,引入一個變數a,a的作用是,將a到x之間的所有節點的根節點全部置為x的根節點,這樣,以後再查詢這些節點的根節點時,就可以直接找到最上面的根節點,而不用通過while迴圈一直往上找,從而實現了路徑壓縮。
最後附上PAT甲級1013的AC程式碼
#include<bits/stdc++.h>
using namespace std;
#define max 1111
#define maxn 500010
int parent[max];
bool vis[max];
void init(){
for(int i = 0;i<max;i++){
parent[i] = -1;
vis[i] = false;
}
}
int find_root(int parent[],int x){
int a = x;
while(parent[ x]!=-1){
x = parent[x];
}
//路徑壓縮
while(a!=x){
int tmp = parent[a];
parent[a] = x;
a = tmp;
}
return x;
}
void connect_vertice(int parent[],int x,int y){
int x_root = find_root(parent,x);
int y_root = find_root(parent,y);
if(x_root!=y_root) parent[x_root] = y_root;
}
bool is_connect(int parent[],int x,int y){
int x_root = find_root(parent,x);
int y_root = find_root(parent,y);
if(x_root==y_root) return true;
else return false;
}
//並查集
int main(){
init();
int N,M,K;
cin>>N>>M>>K;
int highway[maxn][2];
for(int i = 0;i<M;i++){
scanf("%d%d",&highway[i][0],&highway[i][1]);
}
for(int i = 0;i<K;i++){
int current_city;
scanf("%d",¤t_city);
init();
for(int j = 0;j<M;j++){
if(highway[j][0]==current_city||highway[j][1]==current_city){
continue;
}if(is_connect(parent,highway[j][0],highway[j][1])==false)
connect_vertice(parent,highway[j][0],highway[j][1]);
}
int block = 0;
for(int j = 1;j<=N;j++){
if(j==current_city) continue;
int pare = find_root(parent,j);
if(vis[pare]==false) {
block++;
vis[pare] = true;
}
}
block--;
printf("%d\n",block);
}
return 0;
}