并查集模板

模板1:

这里也可以应用一个简单的启发式策略——按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。为了保存秩,需要额外使用一个与 parent 同长度的数组,并将所有元素都初始化为 0。

 1 const int maxn=505;
 2 int parent[maxn],rank_[maxn];
 3 //构造并查集
 4 void p(int n)
 5 {
 6     for(int i=0;i<n;i++)
 7         parent[i]=i;
 8     for(int i=0;i<n;i++)
 9         rank_[i]=0;
10 }
11 //路径压缩
12 int Find(int x)
13 {
14     if(x!=parent[x])
15         x=Find(parent[x]);
16     return parent[x];
17 }
18 //并查集合并
19 void union_p(int x,int y)
20 {
21     if((x=Find(x))==(y=Find(y)))
22         return;
23     if(rank_[x]>rank_[y])
24         parent[y]=x;
25     else
26     {
27         parent[x]=y;
28         if(rank_[x]==rank_[y])
29             rank_[y]++;
30     }
31 }

 

模板2:

除了按秩合并,并查集还有一种常见的策略,就是按集合中包含的元素个数(或者说树中的节点数)合并,将包含节点较少的树根,指向包含节点较多的树根。这个策略与按秩合并的策略类似,同样可以提升并查集的运行速度,而且省去了额外的 rank_ 数组。

这样的并查集具有一个略微不同的定义,即若 parent 的值是正数,则表示该元素的父节点(的索引);若是负数,则表示该元素是所在集合的代表(即树根),而且值的相反数即为集合中的元素个数。

如果要获取某个元素 x 所在集合包含的元素个数,可以使用 -parent[find(x)] 得到。

 1 const int maxn=505;
 2 int parent[maxn],rank_[maxn];
 3 void p(int n)
 4 {
 5     for(int i=0;i<n;i++)
 6     parent[i]=-1;
 7 }
 8 int Find(int x)
 9 {
10     if(parent[x]<0)return x;
11     parent[x]=Find(parent[x]);
12     return parent[x];
13 }
14 void union_(int x,int y)
15 {
16     if((x=Find(x)==(y=Find(y))))
17         return;
18     if(parent[x]<parent[y])
19     {
20         parent[x]+=parent[y];
21         parent[y]=x;
22     }
23     else
24     {
25         parent[y]+=parent[x];
26         parent[x]=y;
27     }
28 }

 

posted @ 2019-04-18 14:17  zuiaimiusi  阅读(270)  评论(0编辑  收藏  举报