[小米] 并查集

简介: 题目描述: 假如已知有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

题目描述:
假如已知有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;
}
目录
相关文章
|
6月前
|
C语言
快速幂+高精乘(填坑)洛谷1226+1045
快速幂+高精乘(填坑)洛谷1226+1045
|
1月前
lanqiao OJ 230 调手表
lanqiao OJ 230 调手表
34 1
|
6月前
|
算法
【错题集-编程题】腐烂的苹果(多源 BFS + 最短路)
【错题集-编程题】腐烂的苹果(多源 BFS + 最短路)
|
6月前
|
算法 测试技术 C#
【欧拉回路】【图论】【并集查找】765. 情侣牵手
【欧拉回路】【图论】【并集查找】765. 情侣牵手
|
6月前
|
存储 人工智能 算法
大数乘法的几种算法分析及比较(2014腾讯南京笔试题)
大数乘法的几种算法分析及比较(2014腾讯南京笔试题)
|
6月前
|
算法 测试技术
联想算法题-小朋友分糖果
联想算法题-小朋友分糖果
42 0
【 腾讯精选练习 50 题】16—三数之和【中等】
【 腾讯精选练习 50 题】16—三数之和【中等】
|
存储 C++
【C++从0到王者】第三十站:二叉树的非递归遍历
【C++从0到王者】第三十站:二叉树的非递归遍历
46 0
|
算法 Java
【洛谷算法题】P5703-苹果采购【入门1顺序结构】
【洛谷算法题】P5703-苹果采购【入门1顺序结构】
松鼠排序(并查集)
松鼠排序(并查集)
56 0