首页 > 其他分享 >并查集——朋友圈,部落问题

并查集——朋友圈,部落问题

时间:2024-06-12 10:14:05浏览次数:10  
标签:pre py 部落 int px 查集 mem 朋友圈 节点

7-2 朋友圈

分数 25 全屏浏览 切换布局 作者 DS课程组 单位 浙江大学

某学校有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
/*并查集,就是把森林变成树,其中的依据就是题目的要求“朋友的朋友就是我的朋友”,
一开始让他们的根节点就是自己,然后通过第一步的join,让他们每个部落联系在一起,具有相同根节点,
find是找到其根节点的函数,并将他自己改成结点的值,便于后续的统计
#include<iostream>
#include<queue>
using namespace std;
const int N=3e4+5;
int n,m;
int res;
int pre[N],cnt[N];
int find(int x){
    while(x!=pre[x]) x=pre[x];
    return x;
}
void join(int x,int y){
    int px=find(x);
    int py=find(y);
    if(px!=py) pre[py]=px;
}
int main(){
cin>>n>>m;
    for(int i=1;i<=n;i++){   //初始化根结点为其自己,建造一棵棵树形成森林
        pre[i]=i;
    }
    while(m--){             //将每一组数联合成一个具有同一个根节点的树,实现森林变树
        int num;cin>>num;
        int fir;cin>>fir;
        num--;
        while(num--){
            int mem;cin>>mem;
            join(fir,mem);//在这个join里面,实现了把值改成了他的根节点的值,便于后续查找统计
        }
    }
    for(int i=1;i<=n;i++){  //统计具有相同根节点的过程,并把结果存在cnt里面
        int k=find(i);
        cnt[k]++;
    }
    for(int i=1;i<=n;i++){     找最大,然后输出
        res=max(res,cnt[i]);
    }
    cout<<res;
}

具体步骤

初始化

在初始化阶段,每个成员都是自己的祖先。

 
for (int i = 1; i <= n; i++) {
    pre[i] = i; // 每个成员的初始祖先是自己
}

处理第一组关系 "3 1 2 3"

这表示成员1、2、3有直接关联,我们需要将它们合并到同一个集合里。

  1. 读取成员数量和第一个成员

     
    int num;
    cin >> num; // num = 3
    int fir;
    cin >> fir; // fir = 1
  2. 合并剩下的成员

     
    num--; // num = 2 (因为第一个成员已经读入)
    while (num--) {
        int mem;
        cin >> mem; // 第一次循环 mem = 2, 第二次循环 mem = 3
        join(fir, mem); // 合并fir和mem所在的集合
    }
  3. 合并过程

    • 第一次循环:mem = 2

       
      join(1, 2);
      • 查找1和2的根节点:  
        int find(int x) {
            while (x != pre[x]) x = pre[x];
            return x;
        }
        因为 pre[1] = 1 和 pre[2] = 2,所以根节点分别是1和2。
      • 合并根节点:  
        if (px != py) pre[py] = px; // pre[2] = 1
        合并后,pre数组变为 [1, 1, 3, 4, 5, 6, 7]
    • 第二次循环:mem = 3

       
      join(1, 3);
      • 查找1和3的根节点: 因为 pre[1] = 1 和 pre[3] = 3,所以根节点分别是1和3。
      • 合并根节点:  
        if (px != py) pre[py] = px; // pre[3] = 1
        合并后,pre数组变为 [1, 1, 1, 4, 5, 6, 7]

此时,成员1、2、3已经在同一个集合中了,它们的代表元素(根节点)都是1。

其他组关系处理

按照相同的逻辑处理其余组关系:

第二组关系 "2 1 4"

  • 合并1和4所在的集合:  
    join(1, 4);
    • 查找1和4的根节点: 因为 pre[1] = 1 和 pre[4] = 4,所以根节点分别是1和4。
    • 合并根节点:  
      if (px != py) pre[py] = px; // pre[4] = 1
      合并后,pre数组变为 [1, 1, 1, 1, 5, 6, 7]

第三组关系 "3 5 6 7"

  • 合并5和6所在的集合:

     
    join(5, 6);
    • 查找5和6的根节点: 因为 pre[5] = 5 和 pre[6] = 6,所以根节点分别是5和6。
    • 合并根节点:  
      if (px != py) pre[py] = px; // pre[6] = 5
      合并后,pre数组变为 [1, 1, 1, 1, 5, 5, 7]
  • 合并5和7所在的集合:

     
    join(5, 7);
    • 查找5和7的根节点: 因为 pre[5] = 5 和 pre[7] = 7,所以根节点分别是5和7。
    • 合并根节点:  
      if (px != py) pre[py] = px; // pre[7] = 5
      合并后,pre数组变为 [1, 1, 1, 1, 5, 5, 5]

第四组关系 "1 6"

  • 已经包含在之前的关系中,无需再处理。

最终统计

通过 find 函数更新每个成员的根节点,并统计每个集合的大小:

 
for (int i = 1; i <= n; i++) {
    int k = find(i);
    cnt[k]++;
}

此时 cnt 数组应该为 [0, 4, 0, 0, 0, 3, 0, 0],表示成员1、2、3、4在一个集合中,成员5、6、7在另一个集合中。

最终输出最大集合的大小:

 
for (int i = 1; i <= n; i++) {
    res = max(res, cnt[i]);
}
cout << res; // 输出 4

所以,最终输出结果为 4,表示具有最多直接和间接关联的成员数目为4。

 

 

标签:pre,py,部落,int,px,查集,mem,朋友圈,节点
From: https://www.cnblogs.com/sly-345/p/18243363

相关文章

  • 算法课程笔记——可撤销并查集
    算法课程笔记——可撤销并查集Gv......
  • 算法课程笔记——并查集基础
    算法课程笔记——并查集基础......
  • 打造朋友圈爆款加盟招商文案,这些技巧你不得不学!
    在社交媒体日益盛行的今天,朋友圈已经成为了一个不可忽视的招商平台,然而随着发广告的人太多,很多人甚至不愿意去看朋友圈。作为一名手工酸奶品牌的创始人,我深知如何通过朋友圈的文案来吸引潜在加盟商的目光。今天,我将分享一些打造朋友圈爆款加盟招商文案的技巧,这些技巧不仅基于......
  • L2-013 红色警报(并查集)
    1.题目L2-013红色警报分数25全屏浏览切换布局作者陈越单位浙江大学战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城......
  • 部落冲突搬砖项目全套教程,轻松上手,赚钱无忧
    ......
  • C130 并查集 P1197 [JSOI2008] 星球大战
    视频链接:  P1197[JSOI2008]星球大战-洛谷|计算机科学教育新生态(luogu.com.cn)//并查集#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintN=400005;inth[N],from[N],to[N],ne[N],idx;voidadd(intu,intv){from[......
  • C129 并查集+01背包 P1455 搭配购买
    视频链接:C129并查集+01背包P1455搭配购买_哔哩哔哩_bilibili  E08【模板】背包DP01背包_哔哩哔哩_bilibiliP1455搭配购买-洛谷|计算机科学教育新生态(luogu.com.cn)//并查集+01背包#include<iostream>#include<cstring>#include<algorithm>usingname......
  • 赛克oj 1540 开心消消乐(并查集、模拟、回溯)
    赛氪OJ-专注于算法竞赛的在线评测系统(saikr.com)题目描述近来,小明的班上风靡着一款名为“开心消消乐”的游戏,为了成为大家眼中的超人,小明开始疯狂研究这款游戏的玩法。游戏的场景是一个......
  • 7-4 并查集【模板】
    给出一个并查集,请完成合并和查询操作。输入格式:第一行包含两个整数N、M,表示共有N个元素和M个操作。接下来M行,每行包含三个整数Zi​、Xi​、Yi​。当Zi​=1时,将Xi​与Yi​所在的集合合并。当Zi​=2时,输出Xi​与Yi​是否在同一集合内,是的话输出Y;否则的话输出N。输出格式:......
  • C126 带权并查集 P1196 [NOI2002] 银河英雄传说
    视频链接:   P1196[NOI2002]银河英雄传说-洛谷|计算机科学教育新生态(luogu.com.cn)//带权并查集#include<iostream>usingnamespacestd;constintN=30005;intT;intp[N],d[N],siz[N];intfind(intx){if(p[x]==x)returnx;intt=find(p[x......