[小米] 并查集
Posted brucemengbm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[小米] 并查集相关的知识,希望对你有一定的参考价值。
题目描写叙述:
假如已知有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;
}
以上是关于[小米] 并查集的主要内容,如果未能解决你的问题,请参考以下文章