码迷,mamicode.com
首页 > 其他好文 > 详细

Algorithm --> 并查集

时间:2015-08-02 23:14:30      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:

并查集

//http://blog.csdn.net/dellaserss/article/details/7724401

首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如:

  1、随意给你两个 点,让你判断它们是否连通;

  2、问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块;

  3、像畅通工程这题,问还需要修几条路,实质就是求有几个连 通分支。如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;

并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,join是合并。

int pre[1000 ];

int find(int x)           //查找根节点
{ 
    int r=x;
    while ( pre[r ] != r )      //返回根节点 r
          r=pre[r ];

    int i=x , j ;
    while( i != r )     //路径压缩
    {
         j = pre[ i ];   // 在改变上级之前用临时变量  j 记录下他的值 
         pre[ i ]= r ;  //把上级改为根节点
         i=j;
    }
    return r ;
}

void join(int x,int y)     //判断x y是否连通     
{
    int fx = find(x);
    int fy = find(y);

    if(fx!=fy)    //如果已经连通,就不用管了; 如果不连通,就把它们所在的连通分支合并起
        pre[fx ]=fy;
}

 

 

递归法:

int father[MAX];   /* father[x]表示x的父节点*/
int rank[MAX];     /* rank[x]表示x的秩*/
  
  
 /* 初始化集合*/
void Make_Set(int x)
{

    father[x] = x; //根据实际情况指定的父节点可变化
    rank[x] = 0;   //根据实际情况初始化秩也有所变化
}
 
 
 /* 查找x元素所在的集合,回溯时压缩路径*/
int Find_Set(int x)
{

    if (x != father[x])
    {
        father[x] = Find_Set(father[x]); //这个回溯时的压缩路径是精华
    }
   return father[x];
 }
 
 
 /* 
    按秩合并x,y所在的集合
    下面的那个if else结构不是绝对的,具体根据情况变化
    但是,宗旨是不变的即,按秩合并,实时更新秩。
 */
 void Union(int x, int y)
{

     x = Find_Set(x);
     y = Find_Set(y);
     if (x == y) return;
     if (rank[x] > rank[y]) 
     {
         father[y] = x;    
     }
     else
     {
         if (rank[x] == rank[y])
         {
            rank[y]++;
         }
        father[x] = y;
     }
}

 

 

例子代码(http://acm.hdu.edu.cn/showproblem.php?pid=1232):

#include<iostream>
using namespace std;

int  pre[1050];
bool t[1050];               //t 用于标记独立块的根结点

int Find(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    
    int i=x,j;
    while(pre[i]!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}

void mix(int x,int y)
{
    int fx=Find(x),fy=Find(y);
    if(fx!=fy)
    {
        pre[fy]=fx;
    }
} 

int main()
{
    int N,M,a,b,i,j,ans;
    while(scanf("%d%d",&N,&M)&&N)
    {
        for(i=1;i<=N;i++)          //初始化 
            pre[i]=i;
        
        for(i=1;i<=M;i++)          //吸收并整理数据 
        {
            scanf("%d%d",&a,&b);
            mix(a,b);
        }
        
        
        memset(t,0,sizeof(t));
        for(i=1;i<=N;i++)          //标记根结点
        {
            t[Find(i)]=1;
        }
        for(ans=0,i=1;i<=N;i++)
            if(t[i])
                ans++;
                
        printf("%d\n",ans-1);
        
    }
    return 0;
}//dellaserss

 

Algorithm --> 并查集

标签:

原文地址:http://www.cnblogs.com/jeakeven/p/4696815.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!