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;
}