题目描述:假如已知有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个不同的元素分成一组不想交的集合。刚开始,每个元素就是一个集合,按照规律将将两个集合进行合并。
刚开始时:有5个人,1~5,开辟一个大小为6的数组,然后都初始化为-1.
然后对集合进行合并。
对于集合{1,2},找每个元素的根节点,1和2的根节点是它自己,然后使1作为根节点,2最为子节点,然后下标为1的值减1,然后下标为2的值变为存它的根节点下标。
然后对于集合{2,3},找每个元素的根节点,2的根节点为1,3的根节点是它自己,可以发现集合{1,2}和集合{2,3}有一个共同元素,然后将它合并,将根节点1的值再减1,将下标为3的值变为存根节点1。
等等,最后图为:
代码为:
#pragma once
class UnionFindSet
{
public:
UnionFindSet(int n)
:_n(n)
{
_a=new int[n+1];
for(size_t i=0;i<=n;++i)
{
_a[i]=-1;
}
}
int FindRoot(int x) //找根节点
{
while(_a[x]>=0) //不是根
{
x=_a[x];
}
return x;
}
void Union(int x1,int x2) //合并
{
int root1=FindRoot(x1);
int root2=FindRoot(x2);
if(root1!=root2)
{
_a[root1]+=_a[root2];
_a[root2]=root1;
}
}
int Count() //统计几个朋友圈
{
int count=0;
for(size_t i=0;i<=_n;++i)
{
if(_a[i]<=-1)
count++;
}
return count-1;
}
protected:
int* _a;
int _n;
};
int friends(int n,int m,int a[][2])
{
UnionFindSet u(5);
for(size_t i=0;i<m;++i)
{
u.Union (a[i][0],a[i][1]);
}
return u.Count ();
}
void TestUnionFindSet()
{
int r[][2]={{1,2},{2,3},{4,5}};
cout<<friends(5,3,r)<<endl; //2
}