PTAzzuli2023天梯赛体验赛3-2门派

PTAzzuli2023天梯赛体验赛3-2门派_第1张图片

题目

在某个江湖中,相互认识的人会加入同一个门派,而互不认识的人不会加入相同的门派。若甲认识乙,且乙认识丙,那么甲和丙就算是认识的。对于给定的认识关系,请计算共有多少个门派,人数最多的门派有多少人。

输入格式

首先输入一个整数T,表示测试数据的组数,然后是T组测试数据。每组测试首先输入两个整数n、m(1≤n≤1000,1≤m≤n(n-1)/2),n表示总人数,m表示认识关系数。然后输入m行,每行两个整数A、B(1≤A,B≤1000,且A!=B),表示编号为A、B的两人互相认识。

输出格式

对于每组测试,输出门派总数和人数最多的门派拥有的人数。

输入样例

2
5 3
1 2
2 3
4 5
5 1
2 5

输出样例

2 3
4 2

思路

本题是一道并查集算法的基础题,解决此类连通块问题,就可以考虑到并查集,具体实现请看代码分析。

代码实现

#include
using namespace std;
class UF{//定义类UF(并查集)
public:
    vectorpre;//父组
    vectorsize;//门派的人数
    UF(int n){
        pre.resize(n);
        size.resize(n,1);//初始人数为1
        for(int i=0;i>t;
    while(t--){
        int a,b,n,i,m,count,ren=0;
        cin>>n>>m;
        UF f(n);//定义对象
        while(m--){
            count=0;
            cin>>a>>b;
            f.merge(a-1,b-1);
        }//数组从0开始
        for(i=0;i

 C语言版本

#include
#include
int pre[1005],size[1005];//定义全局变量,否则新定义函数找不到
int root(int x);               //调用
void merge(int x,int y);       //调用
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int a,b,n,i,m,count,ren=0;
        scanf("%d%d",&n,&m);       
        //初始化每个人对应一个门派
        for(i=0;iren?size[i]:ren;//更新最大人数
            }
        }
        printf("%d %d\n",count,ren);
        memset(size,0,sizeof size);//重新给size赋值为零,为下次使用做准备
    }//输出门派和人数
}
int root(int x){
	return pre[x]=(pre[x]==x?x:root(pre[x]));
}//寻找根,这里采用了路径压缩减少runtime
void merge(int x,int y){
    x=root(x);
    y=root(y);
    if(x!=y){
        pre[x]=y;
        size[y]+=size[x];
    }
}//将两数合并,并且将子门派的人数加入到父门派,并将子门派人数加到父门派

反思

本题采用了并查集,并使用路径压缩的解法来减少runtime是一种高效的查询方式,帮助我们顺利解决连通块问题,可以借此来学习并查集的应用和理解方式。

尾声

希望通过这道题目让大家学会使用并查集,大家多多加油哦~不要忘啦给笔者的点赞关注收藏喔~

PTAzzuli2023天梯赛体验赛3-2门派_第2张图片

你可能感兴趣的:(算法,数据结构)