【第十四课】并查集(acwing-836合并集合 / 做题思路 /c++代码)

目录

错误思路(但能骗分emm)--邻接矩阵(可以跳过)

思路

存在的问题

代码如下

并查集

思路

代码如下

 一些解释


错误思路(但能骗分emm)--邻接矩阵(可以跳过)

思路

刚看到这道题我自己做的时候,因为之前学的trie树的时候意识到使用二维数组的含义,所以在思考这道题的时候也更偏向于使用二维数组。

于是经过不断试错,就想出来了个这种做法:原理就是--图中的邻接矩阵把输入的两个集合编号当作二维数组的下标,执行过M操作的两个集合编号对应的下标会更改为1,"代表"这两个集合合并了,为满足题意我们使用if语句,当两个集合已经执行过"合并"操作,就break。对于Q操作,我们直接判断输入的两个集合编号在二维矩阵中对应的数是否是1就ok了

这样我们表面上能够实现部分"合并"操作某些情况下输入输出是符合题意且正确的

存在的问题

然而这种方法

第一:他其实并没有真正的完成M合并操作,与题意并不相符。

第二:由于我们创建了二维数组,题目要求n的数据范围最大是1e5,我们知道二维矩阵创建应该是n*n的,首先要创建一个1e5*1e5的二维数组本来在大部分计算机上就实现不了,超过了系统可用的内存量;其次我们数组元素是整型int,在32位系统中,其最大索引2.1×10^9,而二维数组元素最多有10^10,从这方面来讲也是不可行的( 在64位系统中,最多可有9.2*10^18,不存在该问题)。

于是我们只能缩小N的取值为1e3,这就已经减少了很多答案。

其实关于邻接矩阵创建二维数组的问题在图的学习中我们已经说过,由于二维数组使用到的坐标可能很少,空间浪费比较严重,我们当时就提出了邻接表的写法。我这里懒得折腾了,就没再思考那一种写法了(doge)。 

数组内存大小限制的因素: 

第三:关于用这种方法得到错误结果的例子:

如果我们执行下面三个操作

M 1 2
M 2 3
Q 1 3

按照我们上面的思路:输出结果会是No。但其实我们首先将1和2合并到同一个集合中,然后将2和3合并到同一个集合中。1、2和3应该都在同一个集合中。

对于第三个原因,在后面使用并查集的代码进行操作时其实结果也是No,因此暂不深入讨论该因素。

因此这种方法是错误的。

代码如下

这里给出按照这种思路能够正确执行的代码 

#include<iostream>
#include<cstring>//引头文件
using namespace std;
const int N=1e3+10;
int p[N],s[N][N],n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
    }
    char op[2];
    while(m--)
    {
        scanf("%s",op);
        int a=0,b=0;
        if(strcmp(op,"M")==0)//对于字符串的比较要用到strcmp函数
        {
            cin>>a>>b;
            if(s[a][b]==1)break;
            else s[a][b]=1;
        }
        else if(strcmp(op,"Q")==0){
            cin>>a>>b;
            bool ans=s[a][b];
            if(ans==1)printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

关于这种方法的正确率什么的我也不是很清楚,只当一种下下策把。 

并查集

其实刚看到这道题,我对这道题题意有一些困惑:合并集合之后的两个集合何去何从了呢?最后他们是都放进了a还是b里呢?另一个集合里面难道是空了么?如果合并之后只会留下一个集合,那么留下两个中的某一个有什么影响呢?还有如果这两个集合里有重复元素怎么办呢?不需要考虑么?

感觉我在题意理解上真是,,,哎

下面是bing的一些解释

思路

我们先明确要实现的两个操作:M 合并两个集合 Q 查询两个集合是否已经合并

我们先想复杂的做法(我甚至这个都没想到😂):怎么实现Q?判断这两个元素是不是在同一个集合里p[x]==p[y],用一个数组p来表示每个元素所属的集合;怎么实现M呢?把其中一个集合里面的所有元素的所属集合也就是p数组的值都更改为另一个数组

Q操作还好,M操作简直是太麻烦了,集合里万一有好多元素呢?怎么一个一个改?

于是我们就想到并查集这种算法:我们用树来表示每个集合,树根的编号就是集合编号。每个节点的元素都存储他的父节点,这个节点的下标代表这个元素本身。

利用这种方式来实现我们的M和Q操作:M操作就是利用while循环找到两个元素所在树的树根 (判断方式是p[x]==x,我们规定根节点的父节点为其自己),然后将其中一个的p[x]指向另一个元素的父节点即可,也就是直接把这个集合这棵树直接连到另一棵树上

关于其中找父节点的过程可以进行优化:当我们找到了一个节点的根节点,那么从根节点到该元素路径上的所有节点的p[x]都应赋值为根节点x,这样就避免了多次重复查找根节点。这也就是我们常说的路径压缩

代码如下

#include<iostream>
using namespace std;
const int N=1e5+10;
int n,m;
int p[N];
int find(int x)
{
    if(p[x]!=x)p[x]=find(p[x]);//路径压缩
    return p[x];//返回根节点 也就是集合编号
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
    }
    while(m--)
    {
        char op[2];
        int a,b;
        scanf("%s%d%d",op,&a,&b);
        if(op[0]=='M')p[find(a)]=find(b);//这里是用一个字符型元素比较的因此可以直接==比较
        else {
            if(find(a)==find(b))printf("Yes\n");
            else printf("No\n");
        }
    }
}

 一些解释

1.op的 if 比较

在上面邻接矩阵的方法里我直接让op这一整个字符数组(即字符串)都与字母进行比较

strcmp(op,"M")==0

注意字符串的比较只能用strcmp函数,不可以直接用== 。补充strcmp函数两个字符串相等返回0,前者小于后者,返回<0的数..。

而在这里,我们直接将op数组第一个元素也就是op[0]与一个字符进行比较,这里就可以直接使用==啦

这个之前好像遇到过很多次了,要记住!

2.puts函数输出

在这里我用了printf函数进行输出,需要写的很多。但是puts函数就可以直接简化书写

if(find(a)==find(b))puts("Yes");
    else puts("No");

这是因为 puts 会自动将换行符 ('\n') 附加到输出中,可以使代码更简洁,并减少忘记包含换行符的机会。简化语法书写。

3.递归函数find

由于我们的优化是,寻找其中一个节点的根节点,那么每次都会不断地向上搜索,而这中间搜索到的节点,也就是从根节点到该元素路径上的所有节点其根节点都是该元素的根节点,都直接赋值为最终的结果。也就达到了优化效果。

如果并未找到根节点(递归出口),就不断执行p[x]=find(p[x]) (递归内容)。还记得递归函数的这两个要素吧~

4.关于传递性

关于这个样例,,,也试了其他博主的博客的代码,执行结果还是No,我也不是很确定关于其传递性的说法了,欢迎指点!!

4 3
M 1 2
M 2 3
Q 1 3
No

好啦并查集就先写到这里,有问题欢迎指出!

期末周也过去了,就好好学算法吧。这几天会先玩一下[😂]希望回来之后是每天日更!!

一起加油!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325759.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

群发邮件的免费软件?做外贸用什么邮箱好?

群发邮件的免费软件有哪些&#xff1f;好用的邮件群发软件&#xff1f; 在数字时代&#xff0c;邮件已成为人们沟通的主要方式之一。有时候&#xff0c;我们需要给大量的联系人发送信息&#xff0c;这时候&#xff0c;群发邮件就显得格外重要。接下来蜂邮就来探讨一下那些值得…

初学者必知的微软.NET6开发环境相关技术介绍

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;看到不少初学者在学习编程语言的过程中如此的痛苦&#xff0c;我决定做点什么&#xff0c;我小时候喜欢看小人书&#xff08;连环画&#xff09;&#xff0c;在那个没有电视、没有手机的年代&#xff0c;这是…

[我的rust付费栏目]rust跟我学(一)已上线

大家好&#xff0c;我是开源库get_local_info的作者带剑书生&#xff0c;get_local_info诞生半个月&#xff0c;现在已经获得500的下载量&#xff0c;并获社区日更前五名&#xff0c;后被西安城市开发者社区收录&#xff08;【我的Rust库】get_local_info 0.1.5发布_rust_科比布…

ChatGPT:人工智能划时代的标志(文末送书)

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 什么是ChatGPT?二. ChatGPT是如何工作的&#xff1f;三. ChatGPT的应用领域四. ChatGPT的优缺点…

自创C++题目——风扇

预估难度 简单 题目描述 有一个风扇&#xff0c;它有个旋转叶片&#xff0c;每个旋转叶片的编号是&#xff0c;请输出它旋转后&#xff0c;中心点与地面的直线距离哪个叶片最近&#xff0c;输出此旋转叶片的编号。默认以“”的形式。 当时&#xff1a; 当或时&#xff0c;…

运筹说 第46期 | 目标规划-数学模型

经过前几期的学习&#xff0c;想必大家已经对线性规划问题有了详细的了解&#xff0c;但线性规划作为一种决策工具&#xff0c;在解决实际问题时&#xff0c;存在着一定的局限性&#xff1a;(1)线性规划只能处理一个目标&#xff0c;而现实问题往往存在多个目标&#xff1b;(2)…

vtk9.3 配置 visual studio 2019 运行环境 和运行实例详解

&#xff08;1&#xff09;包含文件配置&#xff1a; 项目--属性--VC目录&#xff0c;在包含目录中把include文件夹的地址加进去&#xff0c;一直要到下一级 vtk-9.3目录下&#xff0c; 小知识&#xff1a; 在Visual Studio 2019中运行项目时&#xff0c;如果项目中使用了第三…

CTF CRYPTO 密码学-2

题目名称&#xff1a;enc 题目描述&#xff1a; 字符 ZZZZ X XXZ ZZ ZXZ Z ZXZ ZX ZZX XXX XZXX XXZ ZX ZXZZ ZZXZ XX ZX ZZ 分析 此字段是由Z和X组成的字符&#xff0c;联想到莫斯密码是由.和-组成的所以接下来可以尝试莫斯密码解题 解题过程&#xff1a; Step1&#xff1a;…

济南元宇宙赋能新型工业化,助力工业制造业高质量发展

济南工业元宇宙赋能新型工业化&#xff0c;助力工业制造业高质量发展。随着科技的不断发展&#xff0c;新型工业化已成为推动经济发展的重要力量。济南市作为山东省的省会城市&#xff0c;拥有得天独厚的地理优势和资源优势&#xff0c;积极布局工业元宇宙领域&#xff0c;赋能…

12.云原生之kubesphere中应用部署方式

云原生专栏大纲 文章目录 k8s中应用部署Kubernetes常用命令 kubesphere中可视化部署应用创建工作负载服务暴露 helm部署应用helm命令行部署应用kubesphere中使用应用仓库 k8s中应用部署 在k8s中要想部署应用&#xff0c;需要编写各种yaml文件&#xff0c;一旦应用依赖比较复杂…

36V/1.6A两通道H桥驱动芯片-SS8812T可替代DRV8812

由工采网代理的SS8812T是一款双通道H桥电流控制电机驱动器&#xff1b;每个 H 桥可提供输出电流 1.6A&#xff0c;可驱动两个刷式直流电机&#xff0c;或者一个双极步进电机&#xff0c;或者螺线管或者其它感性负载&#xff1b;双极步进电机可以以整步、2 细分、4 细分运行&…

yarn包管理器在添加、更新、删除模块时,在项目中是如何体现的

技术很久不用&#xff0c;就变得生疏起来。对npm深受其害&#xff0c;决定对yarn再整理一遍。 yarn包管理器 介绍安装yarn帮助信息最常用命令 介绍 yarn官网&#xff1a;https://yarn.bootcss.com&#xff0c;学任何技术的最新知识&#xff0c;都可以通过其对应的网站了解。无…

Docker部署Jira、Confluence、Bitbucket、Bamboo、Crowd,Atlassian全家桶

文章目录 省流&#xff1a;注意&#xff1a;解决方案&#xff1a; 1.docker-compose文件2.其他服务都正常启动&#xff0c;唯独Bitbucket不行。日志错误刚启动时候重启后查询分析原因再针对第一点排查看样子是安装的bitbucket和系统环境有冲突问题&#xff1f; 结论&#xff1a…

晶圆表面缺陷检测现状概述

背景&#xff1a; 晶圆表面缺陷检测设备主要检测晶圆外观呈现出来的缺陷&#xff0c;损伤、毛刺等缺陷&#xff0c;主要设备供应商KLA&#xff0c;AMAT&#xff0c;日立等&#xff0c;其中KLA在晶圆表面检测设备占有市场52%左右。 检测设备分类&#xff1a; 电子束设备和光学…

MAC iterm 显示git分支名

要在Mac上的iTerm中显示Git分支名&#xff0c;您需要使用一个名为“Oh My Zsh”的插件。Oh My Zsh是一个流行的Zsh框架&#xff0c;它提供了许多有用的功能和插件&#xff0c;包括在终端中显示Git分支名。 以下是在iTerm中显示Git分支名的步骤&#xff1a; 1、安装Oh My Zsh&…

系统架构11 - 数据库基础(上)

数据库基础 数据库基本概念概述三级模式、两级映像概念模式外模式内模式二级映像逻辑独立性物理独立性 数据库设计需求分析概念结构设计逻辑结构设计物理设计数据库实施阶段据库运行和维护阶段 数据模型E-R模型关系模型模型转换E-R图的联系 关系代数 数据库基本概念 概述 数据…

可持续技术:2024 年技术趋势的绿色创新

随着我们步入2024年&#xff0c;对可持续技术解决方案的关注从未如此强烈。从可再生能源到环保小工具&#xff0c;科技行业正朝着更环保、更可持续的未来大步迈进。 在快速发展的技术领域&#xff0c;创新是推动我们走向可持续未来的动力。随着我们步入2024年&#xff0c;对可持…

高效工作法:占位图片生成工具助力项目快速迭代

在现代设计和开发项目中&#xff0c;图片资源的重要性不言而喻。然而&#xff0c;项目中经常会遇到寻找合适图片、调整图片尺寸和格式等问题&#xff0c;这些问题不仅耗时耗力&#xff0c;还可能影响到项目的进度和质量。此时&#xff0c;占位图片生成工具应运而生&#xff0c;…

【开源】基于JAVA语言的网上药店系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 药品类型模块2.3 药品档案模块2.4 药品订单模块2.5 药品收藏模块2.6 药品资讯模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 药品表3.2.3 药品订单表3.2.4 药品收藏表3.2.5 药品留言表…

[足式机器人]Part2 Dr. CAN学习笔记-Advanced控制理论 Ch04-9 可观测性与分离原理

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Advanced控制理论 Ch04-9 可观测性与分离原理