首页 > 代码库 > [小米] 并查集

[小米] 并查集

题目描写叙述:
假如已知有n个人和m对好友关系(存于数字r)。假设两个人是直接或间接的好友(好友的好友的好友…)。则觉得他们属于同一个朋友圈,请敲代码求出这n个人里一共同拥有多少个朋友圈。
假如:n = 5 。 m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人。1和2是好友,2和3是好友,4和5是好友。则1、2、3属于一个朋友圈,4、5属于还有一个朋友圈,结果为2个朋友圈。

输入:
输入包括多个測试用例。每一个測试用例的第一行包括两个正整数 n、m。1=<n,m<=100000

接下来有m行。每行分别输入两个人的编号f,t(1=<f,t<=n),表示f和t是好友。 当n为0时,输入结束,该用例不被处理。

输出:
相应每一个測试用例,输出在这n个人里一共同拥有多少个朋友圈。

例子输入:
5 3
1 2
2 3
4 5
3 3
1 2
1 3
2 3
0
例子输出:
2
1

解题思路

使用由多棵树组成的森林来解题。每棵树代表一个朋友圈。构建两个数组id和sz,id[x]表示x的根节点,sz[x]表示以x为根节点的树的结点个数。

  • 初始化:for i = 1 to personCount, id[i] = i, sz[i] = 1;
  • 推断输入的一组关系,看两个结点是否位于同一棵树(根节点是否同样)。假设不同,则将较小的树合并到较大的树(将小数根节点的根节点设为大树的根节点)。同一时候将大树的结点个数设置为大树结点与小树结点之和。
    (对于查找函数。为了加快查询速度,能够对路径进行压缩,即将结点的父节点设置为它的祖父结点)
    更具体思路:http://blog.csdn.net/dm_vincent/article/details/7655764

实现代码

#include <iostream>
using namespace std;

class UF
{
public:
    UF(int n)
    {
        id = new int[n];
        sz = new int[n];
        count = n - 1;
        for (int i = 0; i < n; i++)
        {
            id[i] = i;
            sz[i] = 1;
        }
    }

    int getCount()
    {
        return count;
    }

    int findSet(int n)
    {
        while (n != id[n])
        {
            id[n] = id[id[n]];
            n = id[n];
        }

        return n;
    }

    void unionSet(int x, int y)
    {
        int dx = findSet(x);
        int dy = findSet(y);
        if (dx != dy)
        {
            count--;
            if (sz[dx] > sz[dy])
            {
                id[dy] = dx;
                sz[dx] += sz[dy];
            }
            else
            {
                id[dx] = dy;
                sz[dy] += sz[dx];
            }
        }
    }
    ~UF()
    {
        delete [] id;
        delete [] sz;
    }
private:
    int *id;
    int *sz;
    int count;
};


int main()
{
    int personCount;
    while (cin>>personCount, personCount)
    {
        UF *uf = new UF(personCount + 1);
        int relationCount;
        cin>>relationCount;
        int x, y;
        for (int i = 0; i < relationCount; i++)
        {
            cin>>x>>y;
            uf->unionSet(x, y);
        }
        cout<<uf->getCount()<<endl;
        delete uf;
    }
    return 0;
}
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

[小米] 并查集