并查集算法水题(杭电1213)
杭电1213题是一道并查集水题题目链接
并查集算法最重要的是三个部分:查找根结点、路径压缩、合并两个结点。查找根结点的算法和路径压缩的算法差不多。
根结点就是person[a]=a的结点,因为根结点不需要认识别人,都是别人认识他。
这道题虽然使用的路径压缩但没有压缩完全(比如1 2,2 3。程序跑出的结果1的根结点是2),若要输出最后的每个的点的根结点,则需要for循环跑一边find函数。不过这道题完全不需要这么做,只需要输出根结点的数量就是答案了~~,因为我们只关心根结点的数量。
#include<iostream>
#include<cstring>
using namespace std;
int n;
int person[1005];
void init() //并查集数组初始化
{
for(int i=0;i<=n;i++)
person[i]=i; //初始化,假设所有人都不认识别人,只认识自己
}
int find(int a) //寻找根结点
{
int temp=a,root;
while(a!=person[a]) //寻找根结点
a=person[a];
root=a; //找到之后,记录根结点
a=temp; //找回初始的叶节点
while(a!=person[a]) //并查集的路径压缩
{
temp=person[a];
person[a]=root;
a=temp;
}
return root; //返回根结点
}
void merge(int a,int b) //合并
{
int root;
while(a!=person[a]) // 寻找a的根结点
{
root=person[a];
person[a]=b;
a=root;
}
person[a]=b; //将a的根节点变成b
}
int main()
{
int t,a,b,m,fata,fatb,sum;
cin>>t; //输入样例数
while(t--)
{
sum=0;
cin>>n>>m; //输入朋友数、边数
init(); //并查集数组初始化
for(int i=0;i<m;i++)
{
cin>>a>>b;
fata=find(a); fatb=find(b); //寻找各自的根节点
if(fata!=fatb) merge(a,b); //若根节点不同,则合并。若相同则不需要干嘛
}
for(int i=1;i<=n;i++)
if(person[i]==i) sum++; //记录根的数量
cout<<sum<<endl; //输出结果
}
return 0;
}