• 并查集(蓝桥杯 C++ 题目 代码 注解)


    目录

    介绍:

    模板:

    题目一(合根植物):

    代码:

    题目二(蓝桥幼儿园): 

    代码:

    题目三(小猪存钱罐):

    代码:

    题目四(星球大战):

    代码:​​​​​​​

    介绍:

    并查集(Disjoint-set Data Structure),也称为不相交集合数据结构,用于解决集合的合并与查询问题。

    并查集主要支持两个操作:
    1. 合并(Union):将两个不相交的集合合并成一个集合。
    2. 查询(Find):查询元素所在的集合。

    并查集可以用于解决一些集合相关的问题,例如判断两个元素是否属于同一个集合,求集合中的元素个数等。

    并查集的实现通常使用数组和树结构。数组表示每个元素的父节点,树结构表示集合的层次结构。在进行查找操作时,通过递归或迭代找到根节点;在进行合并操作时,将一个集合的根节点连接到另一个集合的根节点上。

    并查集的时间复杂度主要取决于合并和查询操作的路径长度,通常可以达到近似常数时间复杂度。

    例如,假设有5个元素分别为1、2、3、4、5,初始时每个元素都是一个单独的集合:
    [1, 2, 3, 4, 5]

    执行合并操作:将元素1和元素2合并
    [2, 2, 3, 4, 5]

    执行合并操作:将元素2和元素3合并
    [2, 2, 2, 4, 5]

    执行查询操作:查询元素1所在的集合
    2

    执行查询操作:查询元素4所在的集合
    4

    并查集是一种简单且高效的数据结构,可以在解决某些集合问题时提供方便和效率。

    模板:

    1. int find(int x)//查找
    2. {
    3. if (f[x] == x) return x;
    4. return f[x] = find(f[x]);
    5. }
    6. void merge(int x, int y) //合并
    7. {
    8. x = find(x), y = find(y);
    9. if (x != y)
    10. f[x] = f[y];
    11. }

    题目一(合根植物):

    代码:

    1. #include
    2. using namespace std;
    3. int f[1000010];
    4. int find(int k)//查询父亲
    5. {
    6. if (f[k] == k)
    7. return k;
    8. else
    9. {
    10. f[k] = find(f[k]);
    11. return f[k];
    12. }
    13. }
    14. void merge(int a, int b)//合并
    15. int main()
    16. {
    17. int n, m;
    18. cin >> n >> m;
    19. for (int i = 1; i <= n * m; i++)//初始化
    20. {
    21. f[i] = i;
    22. }
    23. int k;
    24. cin >> k;
    25. while (k--)
    26. {
    27. int a, b;
    28. cin >> a >> b;
    29. merge(a, b);//合并
    30. }
    31. long long ans=0;
    32. for (int i = 1; i <= n * m; i++)
    33. {
    34. if (f[i] == i)//父亲为自己则为一个集合的代表
    35. ans++;
    36. }
    37. cout << ans;
    38. }

    题目二(蓝桥幼儿园): 

    代码:

    1. #include
    2. using namespace std;
    3. int n,m;
    4. int f[200100];
    5. int find(int x)//查找
    6. {
    7. if(f[x]==x)
    8. return x;
    9. return f[x]=find(f[x]);
    10. }
    11. void merge(int x,int y)//合并
    12. {
    13. x=find(x),y=find(y);
    14. if(x!=y)
    15. f[x]=f[y];
    16. }
    17. int main()
    18. {
    19. cin>>n>>m;
    20. for(int i=1;i<=n;i++)//初始为自己
    21. f[i]=i;
    22. while(m--)
    23. {
    24. int x,y,z;
    25. cin>>z>>x>>y;
    26. if(z==1)//操作一合并
    27. {
    28. merge(x,y);
    29. }
    30. else//操作二
    31. {
    32. if(find(x)==find(y))
    33. cout<<"YES"<
    34. else
    35. cout<<"NO"<
    36. }
    37. }
    38. }

    题目三(小猪存钱罐):

    代码:

    1. #include //实际上就是几个连通分支
    2. using namespace std;
    3. int n,ans=0;
    4. int f[1001000];
    5. int find(int x)//查找
    6. {
    7. if (f[x] == x) return x;
    8. return f[x] = find(f[x]);
    9. }
    10. void merge(int x, int y) //合并
    11. {
    12. x = find(x),y = find(y);
    13. if (x != y)
    14. f[x] = f[y];
    15. }
    16. int main()
    17. {
    18. cin>>n;
    19. for(int i=1;i<=n;i++)
    20. f[i]=i;
    21. for(int i=1;i<=n;i++)
    22. {
    23. int x;
    24. cin>>x;
    25. merge(x,i);
    26. }
    27. for(int i=1;i<=n;i++)
    28. {
    29. if(f[i]==i)//有一样的则为一个集合里的
    30. ans++;
    31. }
    32. cout<
    33. }

    题目四(星球大战):

    代码:

    1. #include
    2. #include
    3. using namespace std;
    4. int n, f[500100], ans[500100], m, k,cnt=0;
    5. vector<int> e[500100];
    6. int destroys[500100];
    7. int broken[500100];
    8. int find(int x)//查找
    9. {
    10. if (f[x] == x) return x;
    11. return f[x] = find(f[x]);
    12. }
    13. void merge(int x, int y) //合并
    14. {
    15. x = find(x),y = find(y);
    16. if (x != y)
    17. f[x] = f[y];
    18. }
    19. int main()
    20. {
    21. cin >> n >> m;
    22. while (m--)
    23. {
    24. int x, y;
    25. cin >> x >> y;
    26. e[x].push_back(y), e[y].push_back(x);
    27. }
    28. cin >> k;
    29. for (int i = 0; i < k; i++)
    30. {
    31. cin >> destroys[i];
    32. broken[destroys[i]] = 1;//标记为摧毁
    33. }
    34. for (int i = 0; i < n; i++)//初始化父亲点为自身
    35. f[i] = i;
    36. for (int i = 0; i < n; i++)
    37. {
    38. if (broken[i])//被摧毁则跳过
    39. continue;
    40. for (int j = 0; j < e[i].size(); j++)//遍历i点相连的边
    41. {
    42. int tmp = e[i][j];//相邻的点
    43. if (broken[tmp])//被摧毁跳过
    44. continue;
    45. merge(i, tmp);//合并两点为同一连通块
    46. }
    47. }
    48. for (int i = 0; i < n; i++)//遍历所有城市,先找到所有摧毁完后的连通块数
    49. if (!broken[i] && find(i) == i)//该城市没被摧毁且不是自身为父亲节点
    50. cnt++;
    51. for (int i = k - 1; i >= 0; i--)//从后往前修复道路
    52. {
    53. ans[i] = cnt;//记录该城市还没被修复时的连通块数量
    54. broken[destroys[i]] = 0;//修复该点
    55. cnt++;//修复该点,可以成为一个独立的连通分支
    56. for (int j = 0; j < e[destroys[i]].size();j++)//遍历该摧毁点的相连边
    57. {
    58. int v = e[destroys[i]][j];//相邻的点
    59. if (!broken[v] && find(v) != find(destroys[i]))//该城市没被摧毁且二者之前不属于同一连通块
    60. {
    61. merge(v, destroys[i]), cnt--;//因为原本相连,其实二者为同一连通块,合并二者且连通数减一
    62. }
    63. }
    64. }
    65. cout << cnt << endl;//完整时的连通块数量
    66. for (int i=0;i
    67. cout << ans[i] << endl;
    68. }

  • 相关阅读:
    阿里云产品试用系列-容器服务 Serverless AIGC
    外贸客户来源的渠道有哪些?
    用.bat文件做Airtest脚本的多设备批量运行
    Codeforces 9D 卡特兰数,二叉树种类
    【多式联运】基于帝国企鹅算法+遗传算法+粒子群算法求解不确定多式联运路径优化问题【含Matlab源码 2073期】
    安全保护策略:iOS应用程序代码保护的关键步骤和技巧
    Shell脚本大全
    技术分享 | web 控件的交互进阶
    快消品b2b电子商务网站建设方案
    利用Unity和OpenXR实现眼动追踪的基础指南
  • 原文地址:https://blog.csdn.net/qq_74156152/article/details/136574013