并查集是一种高效的数据结构,应用也很广。大一时候简单看了别人的并查集模板,于是生搬硬套过来也A了几道并查集的题目,但是对于其中的一些细节还是不太了解。如今再来看看并查集,有了些新的收获。
初学者推荐一条例题引入并查集。
hdu 1232畅通工程 http://acm.hdu.edu.cn/showproblem.php?pid=1232
首先是初始化根节点par数组和对应的rank数组。如果是简单的题目,rank其实可以省略,但是rank使得并查集算法更高效,且防止了树的退化。
int par[max_n];
int rank[max_n];
void ini(int n)
{
for(int i=0;i<n;i++)
{par[i]=i;rank[i]=0;}
}
par[i]存储了i节点的父节点,如果是 par[i]=i 则代表其本身是父节点。
rank[i]存储了i节点的深度作为附加信息。
先介绍第一种find()
int find(int x)
{
int r=x;
while(par[r] !=r)
r=par[r];
return r;
}
这是最直观的find(),目的只有一个,即为找到父亲节点。
第二种find()
int find(int i)
{
if (par[i] != i)
{
par[i] = find(par[i]);
}
return par[i];
}
递归实现,这个方法就是常说的路径压缩,在找寻父亲节点的过程中更新了par[],减少了复杂度。但是递归实现始终有一个通病:容易栈溢出。RE的一般问题都是出现在这儿。
第三种find()
int find(int x)
{
int r=x;
while(r!=par[r])
r=par[r];
int i=x,j;
while(par[i]!=r)
{
j=par[i];
par[i]=r;
i=j;
}
return r;
}
既达到路径压缩功能,又防止了栈溢出。这是up主使用的方法,推荐使用。
下面就是unite()函数
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
return ;
if(rank[x]<rank[y])
par[x]=y;
else
{
par[y]=x;
if(rank[x]==rank[y])
rank[x]++;
}
}
在unite两个节点x,y时,不仅要做到par的更新,还要更新rank,防止树的退化。
下面方便起见,我定义了一个same函数
bool same(int x,int y)
{
return find(x)==find(y);
}
判断是否属于同一组。
这种数据结构是比较容易实现的,变形也很多。
下面给出hdu1232的代码,就是上述算法的实现:
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
const int max_n=2010;
int par[max_n];
int rank[max_n];
int n;
void ini(int n)
{
for(int i=0;i<n;i++)
{par[i]=i;rank[i]=0;}
}
int find(int x)
{
int r=x;
while(r!=par[r])
r=par[r];
int i=x,j;
while(par[i]!=r)
{
j=par[i];
par[i]=r;
i=j;
}
return r;
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
return ;
if(rank[x]<rank[y])
par[x]=y;
else
{
par[y]=x;
if(rank[x]==rank[y])
rank[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int main()
{
int N,M;
while(scanf("%d",&N)==1)
{
if(N==0)
break;
ini(max_n);
scanf("%d",&M);
int count=N-1;//初始化为N-1条路
while(M--)
{
int a,b;
scanf("%d%d",&a,&b);
if(!same(a,b))//每找到两条已经相连的路就少建设一条路
{
unite(a,b);
count--;
}
}
printf("%d\n",count);
}
return 0;
}
一天又过去了,今天过的怎么样?梦想是不是更远了?