并查集模板

转载于:http://www.tuicool.com/articles/Zb2qYzj

并查集有两个优化。

一、按秩合并

描述:就是在对两个不同子集连接时,按照rank来连,也就是rank低的连在rank高的下面。rank高的做父亲节点。

作用,这样类似维护了一棵树,树是rank高的在上。rank为孩子的数目

// 初始化n个元素
void init(int n)
{
    for(int i=0;i<n;i++)
    {
        parent[i]=i;
        rank[i]=0;   // 初始树的高度为0
    }
}


// 合并x和y所属的集合
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return ;
    if(rank[x]<rank[y])
        parent[x]=y;  // 合并是从rank小的向rank大的连边
    else
    {
        parent[y]=x;
        if(rank[x]==rank[y]) rank[x]++;
    }
}
View Code

二、路径压缩

描述:假如fa数组已经嵌套了N层,那么传统的做法去找祖先要做N次,当N很大时,这种做法很没效率。

这是朴素查找的代码,适合数据量不大的情况

int findx(int x)
{
    int r=x;
   while(parent[r] !=r)
        r=parent[r];
   return r;
}
View Code

下面是采用递归路径压缩的方法查找元素,但是,递归压缩路径可能会造成溢出栈会发生RE

int find(int x)       //查找x元素所在的集合,回溯时压缩路径
{
    if (x != parent[x])
    {
        parent[x] = find(parent[x]);     //回溯时的压缩路径
    }         //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
    return parent[x];
}
View Code

 

下面我们说一下非递归方式进行的路径压缩

int find(int x)
{
    int k, j, r;
    r = x;
    while(r != parent[r])     //查找跟节点
        r = parent[r];      //找到跟节点,用r记录下
    k = x;        
    while(k != r)             //非递归路径压缩操作
    {
        j = parent[k];         //用j暂存parent[k]的父节点
        parent[k] = r;        //parent[x]指向跟节点
        k = j;                    //k移到父节点
    }
    return r;         //返回根节点的值            
}
View Code

 练习https://www.luogu.org/problem/show?pid=3367#sub

#include <stdio.h>
#define N 10020
int parent[N],rank[N],resex[N];
// ³õʼ»¯n¸öÔªËØ void init(int n) { for(int i=0;i<n;i++) { parent[i]=i; rank[i]=0; // ³õʼÊ÷µÄ¸ß¶ÈΪ0 } } int find(int x) { int k, j, r; r = x; while(r != parent[r]) //²éÕÒ¸ú½Úµã r = parent[r]; //ÕÒµ½¸ú½Úµã£¬ÓÃr¼Ç¼Ï k = x; while(k != r) //·ÇµÝ¹é·¾¶Ñ¹Ëõ²Ù×÷ { j = parent[k]; //ÓÃjÔÝ´æparent[k]µÄ¸¸½Úµã parent[k] = r; //parent[x]Ö¸Ïò¸ú½Úµã k = j; //kÒƵ½¸¸½Úµã } return r; //·µ»Ø¸ù½ÚµãµÄÖµ } // ºÏ²¢xºÍyËùÊôµÄ¼¯ºÏ void unite(int x,int y) { x=find(x); y=find(y); if(x==y) return ; if(rank[x]<rank[y]) parent[x]=y; // ºÏ²¢ÊÇ´ÓrankСµÄÏòrank´óµÄÁ¬±ß else { parent[y]=x; if(rank[x]==rank[y]) rank[x]++; } } int main() { int n,m,z,x,y; scanf("%d%d",&n,&m); init(n); for(int i=0;i<m;i++){ scanf("%d%d%d",&z,&x,&y); if(z==1)unite(x,y); if(z==2){ x=find(x); y=find(y); if(x==y)printf("Y\n"); else printf("N\n"); } } return 0; }

 

posted on 2017-03-06 20:03  bennetts  阅读(809)  评论(0编辑  收藏  举报

导航