鱼C论坛

 找回密码
 立即注册
查看: 1573|回复: 4

并查集

[复制链接]
发表于 2023-5-27 21:44:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
问题描述
王希望一些男孩帮他做一个项目。因为这个项目相当复杂,<b>来的男孩越多越好</b>。当然也有一些要求<br><br>王先生选了一个足够大的房间来容纳孩子们。未被选中的男孩必须立即离开房间。房间里有10000000个男孩,一开始的数字从1到10000000。经过王先生的挑选,他们中任何两个仍然在这个房间里的人都应该是朋友(直接或间接),否则就只剩下一个男孩了。考虑到所有的直接朋友配对,你应该决定最好的方式<br>

输入
输入的第一行包含一个整数n(0≤n≤100 000)-直接朋友对的数量。下面的n行分别包含一对数字a和B,由一个空格分隔,这表明a和B是直接的朋友。(A≠B,1≤A,B≤10000000)

输出
一行中的输出正好包含一个整数,等于王可能保留的男孩的最大数量<br>

Sample Input
4
1 2
3 4
5 6
1 6
4
1 2
3 4
5 6
7 8

Sample Output
4
2

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "string.h"

  4. long long int mer[10000002]={0},max[10000002]={0};
  5. long long int i,a,b,imax;
  6. long long int n;

  7. long long int find(long long int x)       
  8. {
  9.         if(x!=mer[x])
  10.         {
  11.                 mer[x]=find(mer[x]);
  12.         }
  13.         max[mer[x]]++;
  14.         if(max[mer[x]]>imax) imax=max[mer[x]];
  15.         return mer[x];
  16. }

  17. void merge(long long int x,long long int y)
  18. {
  19.         long long int fx,fy;
  20.         fx=find(x);
  21.         fy=find(y);
  22.         if(fx!=fy)
  23.         {
  24.                 mer[fx]=fy;
  25.         }
  26. }

  27. int main()
  28. {
  29.     while(scanf("%lld",&n)!=EOF)
  30.     {
  31.             memset(max,0,sizeof(max));
  32.             imax=0;
  33.             for(i=1;i<=10000001;i++)
  34.             {
  35.                     mer[i]=i;
  36.                 }
  37.                    while(n--)        
  38.                 {
  39.                         scanf("%lld%lld",&a,&b);
  40.                         merge(a,b);
  41.                 }
  42.                 printf("%lld\n",imax+1);
  43.         }
  44.        
  45.        
  46.     return 0;
  47. }
复制代码


提示我内存超了,请问应该怎么优化
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-5-27 21:45:05 | 显示全部楼层
你的存储数组 mer 和 max 的大小为 10000002,而题目中男孩的编号仅有 10000000,并且每个男孩只会被遍历一次,因此你可以将数组大小改为 10000001。

同时,如果在参数范围内存在多组数据,你应该在每组数据前清空 mer 和 max 数组,而不是把它们声明成全局变量并只在第一组数据前清空。

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-27 21:47:43 | 显示全部楼层
根据提示信息,你的程序存在内存超限的情况。可以考虑减少对数组的使用。

可以将max数组和mer数组合并,在find函数返回之前记录相关值,这样就没有必要再遍历一遍max数组了。同时,也可以将合并操作优化为按秩合并。

下面是优化后的代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "string.h"

  4. #define MAXN 10000001

  5. long long int fa[MAXN], rank[MAXN], cnt[MAXN];

  6. long long int find(long long int x) {
  7.     if (fa[x] != x) {
  8.         return fa[x] = find(fa[x]);
  9.     }
  10.     return x;
  11. }

  12. void merge(long long int x,long long int y)
  13. {
  14.     long long int fx, fy;
  15.     fx = find(x);
  16.     fy = find(y);
  17.     if (fx != fy) {
  18.         if (rank[fx] > rank[fy]) {
  19.             fa[fy] = fx;
  20.             cnt[fx] += cnt[fy];
  21.         } else {
  22.             fa[fx] = fy;
  23.             cnt[fy] += cnt[fx];
  24.             if (rank[fx] == rank[fy]) {
  25.                 rank[fy]++;
  26.             }
  27.         }
  28.     }
  29. }

  30. int main() {
  31.     long long int n, a, b;
  32.     while(scanf("%lld", &n) != EOF) {
  33.         for (long long int i = 1; i <= MAXN; i++) {
  34.             fa[i] = i;
  35.             rank[i] = 0;
  36.             cnt[i] = 1;
  37.         }
  38.         while(n--) {
  39.             scanf("%lld %lld", &a, &b);
  40.             merge(a, b);
  41.         }
  42.         long long max_cnt = 0;
  43.         for (long long int i = 1; i <= MAXN; i++) {
  44.             if (fa[i] == i && cnt[i] > max_cnt) {
  45.                 max_cnt = cnt[i];
  46.             }
  47.         }
  48.         printf("%lld\n", max_cnt);
  49.     }
  50.     return 0;
  51. }
复制代码


有用请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-27 21:55:56 | 显示全部楼层
sfqxx 发表于 2023-5-27 21:47
根据提示信息,你的程序存在内存超限的情况。可以考虑减少对数组的使用。

可以将max数组和mer数组合并, ...

还是太大....
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-27 22:50:08 | 显示全部楼层


可以考虑优化存储策略,使用一个二维数组来存储朋友对的关系,如`bool friend[MAXN][MAXN]`,用 friend[i ][j] 表示编号为 i 和 j 的男孩是否为朋友。然后再用并查集来处理朋友之间的关系,这样就可以节省掉并查集中的 cnt 数组和 rank 数组了。具体实现时可以将每个男孩看作并查集中的一个节点,当输入直接朋友对时,将对应的节点合并到同一集合中。最后,可以统计并查集中每个集合的大小,找到最大值即可。

另外,还可以考虑使用按需分配的方式来代替全局声明的数组,以便节省内存。对于这个问题,可以使用 C++ 的 STL 容器 `vector` 来保存邻接矩阵`friend`以及并查集数组`fa`。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 10:00

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表