并查集基础(入门)

  最早接触并查集的时候是在做一道最小生成树问题上,当时还不会并查集,题解说用克鲁斯卡尔算法,用并查集来维护,就能够完成最小生成树。

并查集是什么呢?其实,并查集就是一个集合,它有两种操作,一个是合并(merge),一个是查找(getf)。 合并就是说把具有相同祖先的集合合并成

为一个集合,查找就是说,查找某些具有相同祖先的集合。当然这个祖先只是我这样叫的(他其实并不是名义上的祖先),很多时候我们会维护很多

这样的信息,比如说,在求最小生成树的算法中,我们维护的是检查两个顶点是否属于同一个集合,也就是说,判断他们是不是联通,如果联通的话,

那就肯定不能连接这条边的,因为在一个图中,要想找到一棵树,是不能有环存在的(这个到最小生成树的时候再说).

  然后就是效率问题了,我们知道在查找操作中,肯定会因为n的数目过大而超时,所以我们需要用到路径压缩的知识,防止出现一种奇怪的树,也

就是全部左偏或者全部右偏而有需要我们对树的叶子节点进行getf()操作。

先来到有关并查集的最为简单的题目了。

  现在有n个人,分别编号为1,2,3,,,n,然后给出m个关系,比如说:1 2 ,那么1和2就是一个同伙,输出最小的同伙数。

# include<cstdio>
# include<iostream>

using namespace std;

# define MAX 12345

int f[MAX];
int n,m;
int sum;

void init()
{
    for ( int i = 1;i <= n;i++ )
    {
        f[i] = i;
    }
}

int getf( int v )
{
    if ( f[v]==v )
    {
        return v;
    }
    else
    {
        f[v] = getf(f[v]);
        return f[v];
    }
}

void merge( int v,int u )
{
    int t1 = getf(v);
    int t2 = getf(u);

    if ( t1!=t2 )
    {
        f[t2] = t1;
    }
}

int main(void)
{
    cin>>n>>m;
    init();
    for ( int i = 0;i < m;i++ )
    {
        int t1,t2;
        cin>>t1>>t2;
        merge(t1,t2);
    }
    for ( int i = 1;i <= n;i++ )
    {
        if ( f[i]==i )
        {
            sum++;
        }
    }
    cout<<sum<<endl;

    return 0;
}

  有关并查集的东西,以后再更新~

posted @ 2015-03-28 19:42  BYYB_0506  阅读(303)  评论(0编辑  收藏  举报