并查集基础

来源:互联网 发布:乔艾莉·波妮身世知乎 编辑:程序博客网 时间:2024/06/05 10:08

本文章原创作者为:ACdreamers。我对其进行了补充。

并查集是一种树型的数据结构,用于处理一些不相交集合的合并问题

 

并查集的主要操作有:

1-合并两个不相交集合      

2-判断两个元素是否属于同一个集合       

3-路径压缩

 

并查集的两种优化方法:路径压缩与按秩合并。

[cpp] view plain copy
  1. int pre[N],rank[N]; //pre[]为前驱,rank[]为当前元素所在集合的大小  
  2.   
  3. //初始化  
  4. void Init()  
  5. {  
  6.     for(int i=0; i<N; i++)  
  7.     {  
  8.         pre[i] = i;  
  9.         rank[i] = 1;  
  10.     }  
  11. }  
  12.   
  13. //带路径压缩的非递归找根节点  
  14. int Find(int x)  
  15. {  
  16.     int r = x;  
  17.     while(r != pre[r])  
  18.         r = pre[r];  
  19.     int i = x, j;  
  20.     while(i != r)  
  21.     {  
  22.         j = pre[i];  
  23.         pre[i] = r;  
  24.         i = j;  
  25.     }  
  26.     return r;  
  27. }  
  28.   
  29. //带路径压缩的递归找根节点  
  30. int Find(int x)  
  31. {  
  32.     if(pre[x] != x)  
  33.         pre[x] = Find(pre[x]);  
  34.     return pre[x];  
  35. }  
  36.   
  37. //按秩合并,元素少的集合的根节点指向元素多的集合的根节点  
  38. void Union(int x,int y)  
  39. {  
  40.     x = Find(x);  
  41.     y = Find(y);  
  42.     if(x == y) return;  
  43.     if(rank[x] >= rank[y])  
  44.     {  
  45.         pre[y] = x;  
  46.         rank[x] += rank[y];  
  47.     }  
  48.     else  
  49.     {  
  50.         pre[x] = y;  
  51.         rank[y] += rank[x];  
  52.     }  
  53. }  

 

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1856

 

题意:给m个集合,求元素最多的那个集合的元素个数。

参考代码:

# include<cstdio># include<cstring># include<iostream>using namespace std;int ans[10000005];int sum[10000005];int Find(int x){    int r = x;    while(r != ans[r])        r = ans[r];    int i = x, j;    while(i != r)    {        j = ans[i];        ans[i] = r;        i = j;    }    return r;}int main(){    int n,i,a,b,num;    while(scanf("%d",&n)!=EOF)    {        num=1;        for(i=1; i<=10000000; i++)        {            ans[i]=i;            sum[i]=1;        }        for(i=0; i<n; i++)        {            scanf("%d%d",&a,&b);            a=Find(a);            b=Find(b);            if(a!=b)            {                if(sum[a]<=sum[b])                {                    ans[a]=b;                    sum[b]=sum[a]+sum[b];                    if(sum[b]>num) num=sum[b];                }                else                {                    ans[b]=a;                    sum[a]=sum[a]+sum[b];                    if(sum[a]>num) num=sum[a];                }            }        }        printf("%d\n",num);    }    return 0;}

 

 

 

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1272

 

题意:给定点集,要判断是否任意两点只有一条路径,如果直接用枚举任意两点,再判断是否有两条路径理论上是可以的,但是计算量太大,超时。只需判断形成它们形成的图是否无环且连通。

 

分析:先把所有的点的父亲节点指向自己,然后用并查集合并,每次把合并的两个点标记为访问过的,如果中间出现要合并的两个节点的根节点都相同,说明有环,如果最后在访问过的节点中有大于1个节点的父亲节点还是自己,说明不连通。




题目:http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=212

 

题意:求一个元素所在的集合的所有元素的个数。

 

分析:直接合并即可。


原创粉丝点击