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