热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python之并查集洛谷蓝桥杯

同时正在备战蓝桥杯题解如有不足请多批评指正大一双非本科在读目标是进大厂洛谷:亲戚关系题目链接问题分析:这是一道考察并查集的经典例题。何为并查集ÿ

同时正在备战蓝桥杯 题解如有不足请多批评指正  

大一双非本科在读

目标是进大厂 

洛谷:亲戚关系 题目链接

问题分析:这是一道考察并查集的经典例题。

何为并查集?并查集是一种(树型)数据结构 ,用于处理一些不相交集合的合并查询问题。

思想:用一个数组表示了整片森林,树的根节点唯一标识了一个集合,我们只要找到了某个元素的的树根,就能确定它在哪个集合里。

例如给出数组parent=[0,1,5,1,3,1],parent[i]代表结点i的父结点(很形象吧!?)

观察数组,我们知道:parent[2]=5 ,说明了结点2的父节点是5

再来:parent[5]=1,说明了结点5的父节点是1

再来:parent[1]=1,说明了结点1的父节点是1

对上面这行可能有疑惑:我们先记住,若parent[i]=i  则i是一个集合内的根节点

那么他有什么作用:如果一个结点j 它的父节点的父节点的父节点的父节点.....是i

说明了j和它的父节点和它的父节点的父节点和....一共这么多结点,对于每一个结点,都可以访问到i结点。我们不如把它叫做祖先(能够访问 类似于 含有血缘关系,你和你的祖先,你的父亲的祖先,你的父亲的父亲的祖先都有血缘关系。)

因此这么多结点就构成了一个集合(代表集合的对象是根节点(祖先))

所以对于刚刚提到的数组,由于结点5可以访问到祖先>>1,所以5和1有血缘关系,即5属于祖先1代表的集合,由于结点2的父节点是5,所以它可以通过父节点5访问到祖先>>1,所以2和1有血缘关系,即2属于祖先1代表的集合。

因此我们要判断两个结点是否属于同一个集合,可以借助访问各自的祖先加以判断。

如果祖先相同,那么属于同一集合,否则不属于同一集合。

对于上述数组结点0和结点1就不属于同一集合

所以下面给出访问祖先的代码:(关于优化下面会阐述)

def find_root(x):while x!=parent[x]:3如果不是祖先 就访问自己的父节点x=parent[x]return x

 那么上面这段代码就是代表了并查集的思想之一:查询

那么下面我们研究并查集的另一个思想:合并


再次给出上面那个例子parent=[0,1,5,1,3,1]

我们知道结点1,2,3,4,5同属于一个集合(用结点1来标识)

由于parent[0]=0 说明0是一个集合的祖先,这个集合用结点0来标识

由于以结点0为代表的集合元素个数为1,比较特殊,我们不妨给他(集合)添加两个结点

分别是结点6,结点7,因此parent=[0,1,5,1,3,1,0,0]

所以现在 结点0,6,7同属于一个集合(用结点0来标识)

下面研究合并,何为合并?就是将两个集合变为为一个集合

容易想到,我们可以把结点0(祖先)作为结点1的子结点,换句话说,把结点1作为结点0的父节点。

那么这样子有什么用:我们知道用结点0来标识的集合中的结点,都可以访问到结点0,现在结点0又可以访问到结点1,所以用结点0来标识的集合中的结点,都可以访问到结点1,因此用结点1来标识的集合 结点数目扩大了! 这不正达到了我们想要的效果吗?

简言之 集合A和集合B原本分属两大家族,把A的祖先作为B祖先的孩子,因而集合A和B中的所有结点都有了血缘关系,实现了家族合并。

 所以下面给出合并的代码:

def union(x,y):#合并x_root,y_root=find(x),find(y)parent[x_root]=y_root#一般的x_root!=y_root,直接合并过去#如果x_root=y_root,合并本身,没有发生任何变化

 所以 代码就可写出了:

def find_root(x):while x!=parent[x]:x=parent[x]return xdef union(x,y):x_root=find_root(x)y_root=find_root(y)parent[x_root]=y_rootn,m,p=map(int,input().strip().split())parent=[i for i in range(n+1)]#初始化for i in range(m):#h合并tmp=list(map(int,input().strip().split()))union(tmp[0],tmp[1])for j in range(n):#判断tmp=list(map(int,input().strip().split()))if find_root(tmp[0])==find_root(tmp[1]):print('Yes')else:print('No')

 但是这样超时 所以需要进行优化:

先分析超时的原因:还是利用上面给出的数组parent=[0,1,5,1,3,1,0,0](未合并)

我们可以画出下面这样的关系图:

 所以科学家们给出了一种方法:路径压缩。

简言之,对于上图,比如在访问4的根节点的时候,经过图中标识的''很长''一段路径,这一段路径由许许多多的结点构成,它们有一个共同特点就是根节点都是1,那么路径压缩要做的就是把这条路径上的所有结点的父节点设为结点1

这样子的作用:比如我下一次查询结点3的根节点的时候,只需要1次,原来需要9999次!

def find_root(x):#返回根节点if x!=parent[x]:#只要不是根节点parent[x]=find_root(parent[x])#修改父节点为根结点return parent[x]#返回根节点(父节点)

 第一次接触路径压缩如果不太好理解,可以先和小郑一样把这个模板记下来~


n,m,p=map(int,input().strip().split())parent=[i for i in range(n+1)]def find_root(x):#返回根节点if x!=parent[x]:#只要不是根节点parent[x]=find_root(parent[x])#把x的父节点设为根节点return parent[x]def union(x,y):x_root=find_root(x)y_root=find_root(y)parent[x_root]=y_rootfor i in range(m):tmp=list(map(int,input().strip().split()))union(tmp[0],tmp[1])for j in range(p):tmp=list(map(int,input().strip().split()))if find_root(tmp[0])==find_root(tmp[1]):print('Yes')else:print('No')

 

 可见路径压缩帮助我们优化了算法

蓝桥杯真题实战:七段码(第十一届试题E填空压轴)>>考察并查集

代码设计分析:题目就是在问一个连通性问题,从7条边选几个出来判断是不是连通图。

也就是判断是不是属于同一个集合的问题。首先明确一点,并查集两大功能:查找与合并。要先合并,再查找(没有合并一个集合那拿什么来查找?)。所以,相当于我们要先构建亲戚关系网,最后判断所有结点的祖先是否都是同一个,如果是则连通,否则不连通。

那么构建亲戚关系的条件:如果两个顶点直接相连,那么把那个点所属的集合与另外一个点所属的集合合并。当所有的点合并完了,只需要遍历所有的点的祖先,判断是否都是同一个,如果是,大功告成,count加1

def find_root(x):if x!=parent[x]:parent[x]=find_root(parent[x])return parent[x]def union(x,y):x_root,y_root=find_root(x),find_root(y)if x_root!=y_root:parent[x_root]=y_rootedge=[[0]*7 for i in range(7)]#设一个0号进去,无边与其相连l=[0,1,2,3,4,5,6]
edge[0][1]=edge[0][2]=edge[1][3]=edge[1][4]=edge[2][3]=1
edge[3][4]=edge[3][5]=edge[4][6]=edge[5][6]=edge[2][5]=1#有边相连记作1for i in range(7):for j in range(7):edge[i][j]=max(edge[i][j],edge[j][i])#无向图对称import itertoolscount=0for i in range(1,8):#灯泡数目for j in itertools.combinations(l,i):#比如[(1,2,3),[1,2,4]]parent=[i for i in range(7)]#判断两两是否连通for k in range(0,i):for p in range(k+1,i):if edge[j[k]][j[p]]==1:#如果连通,合并union(j[k],j[p])for m in range(i-1):#判断属于是否同一集合(最终所有的)if find_root(j[m])!=find_root(j[m+1]):breakelse:print(j)#显示符合条件的数据,可删去count+=1
print(count)
#答案80

 我是小郑 正在奔赴热爱 奔赴山海!


推荐阅读
  • Python进阶笔记:深入理解装饰器、生成器与迭代器的应用
    本文深入探讨了Python中的装饰器、生成器和迭代器的应用。装饰器本质上是一个函数,用于在不修改原函数代码和调用方式的前提下为其添加额外功能。实现装饰器需要掌握闭包、高阶函数等基础知识。生成器通过 `yield` 语句提供了一种高效生成和处理大量数据的方法,而迭代器则是一种可以逐个访问集合中元素的对象。文章详细解析了这些概念的原理和实际应用案例,帮助读者更好地理解和使用这些高级特性。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • HBase Java API 进阶:过滤器详解与应用实例
    本文详细探讨了HBase 1.2.6版本中Java API的高级应用,重点介绍了过滤器的使用方法和实际案例。首先,文章对几种常见的HBase过滤器进行了概述,包括列前缀过滤器(ColumnPrefixFilter)和时间戳过滤器(TimestampsFilter)。此外,还详细讲解了分页过滤器(PageFilter)的实现原理及其在大数据查询中的应用场景。通过具体的代码示例,读者可以更好地理解和掌握这些过滤器的使用技巧,从而提高数据处理的效率和灵活性。 ... [详细]
  • 在 Vue 应用开发中,页面状态管理和跨页面数据传递是常见需求。本文将详细介绍 Vue Router 提供的两种有效方式,帮助开发者高效地实现页面间的数据交互与状态同步,同时分享一些最佳实践和注意事项。 ... [详细]
  • 本文探讨了一种高效的算法,用于生成所有数字(0-9)的六位组合,允许重复使用数字,并确保这些组合的和等于给定的整数N。该算法通过优化搜索策略,显著提高了计算效率,适用于大规模数据处理和组合优化问题。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 每年,意甲、德甲、英超和西甲等各大足球联赛的赛程表都是球迷们关注的焦点。本文通过 Python 编程实现了一种生成赛程表的方法,该方法基于蛇形环算法。具体而言,将所有球队排列成两列的环形结构,左侧球队对阵右侧球队,首支队伍固定不动,其余队伍按顺时针方向循环移动,从而确保每场比赛不重复。此算法不仅高效,而且易于实现,为赛程安排提供了可靠的解决方案。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 【图像分类实战】利用DenseNet在PyTorch中实现秃头识别
    本文详细介绍了如何使用DenseNet模型在PyTorch框架下实现秃头识别。首先,文章概述了项目所需的库和全局参数设置。接着,对图像进行预处理并读取数据集。随后,构建并配置DenseNet模型,设置训练和验证流程。最后,通过测试阶段验证模型性能,并提供了完整的代码实现。本文不仅涵盖了技术细节,还提供了实用的操作指南,适合初学者和有经验的研究人员参考。 ... [详细]
  • 深入解析:React与Webpack配置进阶指南(第二部分)
    在本篇进阶指南的第二部分中,我们将继续探讨 React 与 Webpack 的高级配置技巧。通过实际案例,我们将展示如何使用 React 和 Webpack 构建一个简单的 Todo 应用程序,具体包括 `TodoApp.js` 文件中的代码实现,如导入 React 和自定义组件 `TodoList`。此外,我们还将深入讲解 Webpack 配置文件的优化方法,以提升开发效率和应用性能。 ... [详细]
  • 本课程深入探讨了 Python 中自定义序列类的实现方法,涵盖从基础概念到高级技巧的全面解析。通过实例演示,学员将掌握如何创建支持切片操作的自定义序列对象,并了解 `bisect` 模块在序列处理中的应用。适合希望提升 Python 编程技能的中高级开发者。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 针对图像分类任务的训练方案进行了优化设计。通过引入PyTorch等深度学习框架,利用其丰富的工具包和模块,如 `torch.nn` 和 `torch.nn.functional`,提升了模型的训练效率和分类准确性。优化方案包括数据预处理、模型架构选择和损失函数的设计等方面,旨在提高图像分类任务的整体性能。 ... [详细]
  • 本文详细介绍了使用 Python 进行 MySQL 和 Redis 数据库操作的实战技巧。首先,针对 MySQL 数据库,通过 `pymysql` 模块展示了如何连接和操作数据库,包括建立连接、执行查询和更新等常见操作。接着,文章深入探讨了 Redis 的基本命令和高级功能,如键值存储、列表操作和事务处理。此外,还提供了多个实际案例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 在 CentOS 6.5 系统上部署 VNC 服务器的详细步骤与配置指南
    在 CentOS 6.5 系统上部署 VNC 服务器时,首先需要确认 VNC 服务是否已安装。通常情况下,VNC 服务默认未安装。可以通过运行特定的查询命令来检查其安装状态。如果查询结果为空,则表明 VNC 服务尚未安装,需进行手动安装。此外,建议在安装前确保系统的软件包管理器已更新至最新版本,以避免兼容性问题。 ... [详细]
author-avatar
帝·姬
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有