1. 程式人生 > 其它 >PAT甲級1013並查集筆記(路徑壓縮)

PAT甲級1013並查集筆記(路徑壓縮)

技術標籤:c++演算法

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",&current_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; }