POJ 2524 并查集

POJ 2524 并查集

之前这个问题用深度优先搜索做的。。耗时很长,很显然这是一个并查集的题目:

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
vector <int> a[50001];
int n,m,col;
bool v[50001];
void dfs(int k)
{
    int i,j;
    v[k]=1;
    for(i=0;i<a[k].size();i++)
        if(v[a[k][i]]==0)dfs(a[k][i]);
}    
int main()
{
    int i,j,p,q,cn=0;
    while(scanf("%d %d",&n,&m),n||m)
    {
        for(i=1;i<=n;i++)a[i].clear(),v[i]=0;
        for(i=0;i<m;i++)scanf("%d %d",&p,&q),a[p].push_back(q),a[q].push_back(p);
        col=0;
        for(i=1;i<=n;i++)if(v[i]==0)dfs(i),col++;
        printf("Case %d: %d\n",++cn,col);    
    }    
    return 0;
}    

 

 

并查集版本:

#include <iostream>
using namespace std;

#define MAXN 500001
struct
{
     int parent;
     int rank;
}UFS[MAXN];          //UnionFindSet   UFS

//其中Parent为正数时表示该节点的父节点下标,为负数时表示该节点为一个根节点,其绝对值为该集合包含的节点总数。
//rank表示权值,在不同问题中有不同的含义。

void MakeSet(int N)     /* 初始化 */
{
     int i;

     for(i=0;i<=N;i++)      //额外增加一位,从0开始可以从1开始也可以
     {
         UFS[i].parent=-1;  /* 开始每个节点单独构成一个集合 */
         UFS[i].rank=0;     /* 权值视具体情况付初值 */
     }
}

int Root(int x)     /* 查找包含接点x的集合的根节点 */

{
     int i=x,temp;
     while(UFS[i].parent>0)
         i=UFS[i].parent;

     while(i!=x)     /* 压缩路径以提高以后检索效率 */
     {
         temp=UFS[x].parent;            
         UFS[x].parent=i;               //直接将x的祖先命为根节点
         x=temp;                                 //继续处理x的原祖先
     }
     return i;
}

void Union1(int a,int b)     /* 合并a和b所在的集合 */
{
     int fa,fb;
     fa=Root(a);
     fb=Root(b);
     if(fa==fb) return;

     if(UFS[fa].parent<UFS[fb].parent)     /* 始终将较小树作为较大树的子树 */
     {
         UFS[fa].parent+=UFS[fb].parent;
         UFS[fb].parent=fa;
     }
     else
     {
         UFS[fb].parent+=UFS[fa].parent;
         UFS[fa].parent=fb;
     }
}
void Union2(int a, int b)     //将rank较大的作为父节点
{
    int x = Root(a), y = Root(b);
    if( x == y ) return ;
    if( UFS[x].rank > UFS[y].rank ) UFS[y].parent = x;
    else{
        UFS[x].parent = y;
        if( UFS[x].rank == UFS[y].rank ) UFS[y].rank++;
    }
}

int main()
{
    int N, M, a, b;
    int nCases = 1;
    while(scanf("%d %d", &N, &M) && (M||N))
    {
        MakeSet(N);
        for(int i=1; i<=M; ++i)
        {
            scanf("%d %d", &a, &b);
            a = Root(a);
            b = Root(b);
            //如果a,b不在同一个集合,则合并
            if(a != b)
            {
                N--;
                Union2(a, b);
            }
        }
        printf("Case %d: %d\n", nCases++, N);
    }
    return 0;
}

今天明天总结一下并查集的相关知识吧!

你可能感兴趣的:(POJ 2524 并查集)