假设一张桌子可坐无限多人,小明准备邀请一些朋友来,所有有关系的朋友都可以坐同一张桌,没有关系的则要另开一桌,问需要多少张桌子(小明不坐,不考虑小明与其他人的关系)?
思路:常规的并查集。要求出所有人的老大,有几个老大就要几张桌子。那么有关系的都归为同一个老大。用数组实现,再顺便压缩路径。
一共有四个板块:
1,赋初值
2,合并
3,查找上一级并路径压缩
4,查找共有几个团体。(set容器在这里很方便)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#include <bits/stdc++.h>
int dad[10001];
void chushi(int n) //初始化,把每个人的老大变成自己
{
for(int i=1; i<=n; i++)
dad[i]=i;
return;
}
int find(int x) //查询x的根节点并路径压缩
{
if(dad[x]!=x)
dad[x] = find(dad[x]); //find找到老大并将老大作为他的上一级。
return dad[x]; //返回老大的值
}
int check(int n) //查找有几位老大,需要几张桌子
{
set<int>sett; //用set容器查找
for(int i=1;i<=n;i++) //查漏,将所有的成员再归一下类
find(i);
for(int i=1;i<=n;i++) //将所有成员的老大放入set
sett.insert(dad[i]);
return sett.size(); //返回set中有几种老大
}
int join(int a,int b) //合并
{
a=find(a);
b=find(b);
if(a!=b) //将a的上一级变为b
dad[a]=b;
}
int main()
{
int t,n,m,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
chushi(n);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
join(a,b);
}
printf("%d\n",check(n));
}
}