朋友圈
某学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出,如果A和B是朋友,且B和C是朋友,则A和C也是朋友。请编写程序计算最大朋友圈中有多少人。
输入格式:
输入的第一行包含两个正整数N(≤30000)和M(≤1000),分别代表学校的学生总数和俱乐部的个数。后面的M行每行按以下格式给出1个俱乐部的信息,其中学生从1~N编号:第i个俱乐部的人数Mi(空格)学生1(空格)学生2 … 学生Mi
输出格式:
输出给出一个整数,表示在最大朋友圈中有多少人。
输入样例:
7 4
3 1 2 3
2 1 4
3 5 6 7
1 6
输出样例:
4
这题是经典的并查集题目
那么先讲解何为并查集
这边引用别的博主的一张图片
假设分为明教,少林寺,峨嵋派,西毒四个帮派,在帮派战争中,队友如何识别队友和敌人呢,
比如金毛狮王和紫衫龙王如何知道自己是队友呢,答案就是他们有个教主叫做张无忌,其他人
也是一样,例如小昭和胡青牛,他们有共同的上级紫衫龙王,紫衫龙王有上级张无忌,殷野王上级有白眉鹰王,白眉鹰王上级有张无忌,所以他们全部都隶属于张无忌的部下,那么他们就知道对方是不是自己的队友。
并查集也是如此,我们要将一群一群的数据分类,如何知道这个数据是这个类呢,只要设置一个根
所有的祖先节点都为这个根,就知道他们都是同一个类,否则不是。
因此并查集就要有两个函数 find(int target) 和 union(int x,int y)
find函数用来查找目标数的祖先数,union用来将一个数并入另一个数的类中。
find如何操作呢:首先设置pre[]数组 初始化时还没分类 每个人单独为一个类 那么pre[ i ] = i;
当union将这个数并入一个类的时候,i 的祖先结点就不是它本身了,而是另一个j 属的类的祖先结点 也就是 将j的祖先结点赋值为i的祖先结点 pre[ i ] = pre[ j ] 这就是union的操作
那么find查找的祖先结点的时候只要 return pre[ i ]就可以了
下面附上上面那题朋友圈的代码 帮助理解
#include<bits/stdc++.h>
using namespace std;
const int N=30005; //指定并查集所能包含元素的个数(由题意决定)
int pre[N]; //存储每个结点的前驱结点
int rank1[N]; //树的高度
int find(int x) //改进查找算法:完成路径压缩,将 x的上级直接变为根结点,那么树的高度就会大大降低
{
if(pre[x] == x) return x; //递归出口:x的上级为 x本身,即 x为根结点
pre[x] = find(pre[x]);
return pre[x]; //此代码相当于先找到根结点 rootx,然后 pre[x]=rootx
}
bool isSame(int x, int y) //判断两个结点是否连通
{
return find(x) == find(y); //判断两个结点的根结点(即代表元)是否相同
}
bool join(int x,int y)
{
x = find(x); //寻找 x的代表元
y = find(y); //寻找 y的代表元
if(x == y) return false; //如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,返回 false,表示合并失败;否则,执行下面的逻辑
if(rank1[x] > rank1[y]) pre[y]=x; //如果 x的高度大于 y,则令 y的上级为 x
else //否则
{
if(rank1[x]==rank1[y]) rank1[y]++; //如果 x的高度和 y的高度相同,则令 y的高度加1
pre[x]=y; //让 x的上级为 y
}
return true; //返回 true,表示合并成功
}
int main(){
int n,m;
cin>>n>>m;
for(int i = 0; i < n; i++){
pre[i] = i; //每个结点的上级都是自己
rank1[i] = 1; //每个结点构成的树的高度为 1
}
int num;
int pre,temp;
for(int i=0;i<m;i++)
{
cin>>num;
for(int j =0;j<num;j++)
{
cin>>temp;
if(j==0)
{
pre = temp;
continue;
}
if(find(pre) != find(temp))
join(temp,pre);
}
}
map<int,int>mp;
int msxx=0;
for(int i = 1;i<=n;i++)
{
mp[find(i)]++;
if(mp[find(i)]>msxx)
{
msxx = mp[find(i)];
}
}
cout<<msxx;
}