Python 蓝桥杯之拓扑排序 检测环

简介: Python 蓝桥杯之拓扑排序 检测环

了解拓扑排序之前,先了解AOV网:

image.png

有向图中若以顶点表示活动,有向边表示活动之间的先后关系,这样的图简称为AOV网

比如C1指向C4,说明C4活动的开展以C1的开展为前提(C1没完成就不能去弄C4)

知道了AOV网图,就可以引入拓扑序列的概念:

拓扑序列:拓扑序列是顶点活动网(AOV网)中将活动按发生的先后次序进行的一种排列

这么说有点抽象,传送门:某站上视频对这个讲解的很好

值得一提的是:任何一个有向无环图一定有拓扑序列,因此拓扑序列可以用来检测环

拓扑排序之前,先了解有向图的三个基本概念:入度,出度,度

入度:指向该顶点的入边 出度:从该顶点指出的边    度:入度和出度的总和(与顶点相关联的边的条数)

从图上来看,拓扑排序需要这么做(视频里也有详细的分析过程,建议去看,强烈建议):

image.png

那么对于代码来说,我们需要运用深搜的思想来执行拓扑排序的操作,1:找到图中入度为0的顶点 压栈 2:处于栈顶的顶点出栈 并加入列表(另外创建的存储结构,用于存储拓扑序列中的元素) 访问该顶点的所有邻居,如果其存在入度为0的邻居,压栈,执行操作2,如果不存在,回溯。


下面以上图为例,将C1,C2...C7依次对应为字母abcdefg,给出创建拓扑序列的代码:

#准备工作上需要一个字典:用于存放连接关系
def topsort(graph):
    #初始化所有点的入度为0
    indegrees=dict((i,0) for i in graph.keys())
    #传入入度大小
    for i in graph.keys():
        for j in graph[i]:
            indegrees[j]+=1#'a':'cd',代表a指向c和d,那么c和d的入度增加1
    #获取入度为0的顶点
    stack=[i for i in indegrees.keys() if indegrees[i]==0]
    #创建拓扑序列
    seq=[]
    while stack:#深搜
        tmp=stack.pop()#出栈
        seq.append(tmp)#加入拓扑序列
        for k in graph[tmp]:#遍历邻居,邻居入度-1,邻居入度为0入栈
            indegrees[k]-=1
            if indegrees[k]==0:
                stack.append(k)
    if len(seq)==len(graph):
        print(seq)#输出拓扑序列
    else:
        print('存在环')#当存在环,最终余下的点入度都不为0,Seq个数少于总顶点数
G={
    'a':'cd',
    'b':'df',
    'c':'e',
    'd':'efg',
    'e':'g',
    'f':'g',
    'g':''
}
topsort(G)
#['b', 'a', 'd', 'f', 'c', 'e', 'g']


蓝桥杯真题演练:


image.png


第一次没优化只有71分,优化了第二次是85。(这最后一个如有大佬知道怎么过的请教一下)

image.png

代码设计思路:找能够组成圈的所有点,根据这些点找到最大环。


首先解决如何计算圈的大小问题:比如A结点经过一系列结点最后回到了A结点,我们要知道圈的大小,只需要知道这一过程中A走过了几个不同的结点,换句话说,这个圈内有几个元素(集合的思想)。然后比较各个圈的大小即可知道最大环。


这里有一点需要强调:虽然我们可以通过遍历每个点(能够组成圈的点),枚举出所有圈大小的情况,但是会有重复,当数据大起来,就会超时(71)。那怎么样才能避免重复呢,思考,比如题目给出的实例,2,3,4,5组成一个圈,假设我在遍历结点2的时候,计算出了这个圈的大小是4,那么圈内的结点,在下一次访问都不需要再访问了,也就是说下一次可以直接访问结点6。


原因:问题就在于圈内的结点有没有可能与其他结点组成更大的圈,如果我们不再访问,会不会导致范围缩小或者遗漏?答案是不会的。因为,如果要组成更大的圈,圈内的结点必然要与圈外的结点连接。由于圈内的结点是作为圈的一部分,那么必定已经有一条边指向这个结点。如果存在这个结点与圈外的结点构成更大的圈,那么必然与圈外的结点有连接,那么这个结点就会同时指向两个结点,就不符合题意了。


#准备工作上需要一个字典:用于存放连接关系
def topsort(graph):
    #初始化所有点的入度为0
    indegrees=dict((i,0) for i in graph.keys())
    #传入入度大小
    for i in graph.keys():
        indegrees[graph[i]]+=1
    #获取入度为0的顶点
    stack=[i for i in indegrees.keys() if indegrees[i]==0]
    #创建拓扑序列
    seq=[]
    while stack:#深搜
        tmp=stack.pop()#出栈
        seq.append(tmp)#加入拓扑序列
        for k in graph[tmp]:#遍历邻居,邻居入度-1,邻居入度为0入栈
            indegrees[k]-=1
            if indegrees[k]==0:
                stack.append(k)
    if len(seq)==len(graph):
        print(seq)#对于本题而言一定有圈
    else:
        ans=0#最大圈的大小
        res=[i for i in indegrees if indegrees[i]!=0]#环上的点
        found=[]#用于减少次数:已查找过的点
        for j in res:#寻找最大环
            if j not in found:
                start=j
                p=set()
                while G[j]!=start:
                    found.append(j)
                    p.update([int(j)])
                    j=G[j]
                found.append(j)
                p.update([int(j)])
                ans=max(ans,len(p))
        print(ans)
n=int(input().strip())
m=list(map(int,input().strip().split()))
G={}
for i in enumerate(m):
    G[str(i[0]+1)]=str(i[1])
topsort(G)


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


目录
相关文章
|
6天前
|
Java 数据处理 索引
(Pandas)Python做数据处理必选框架之一!(二):附带案例分析;刨析DataFrame结构和其属性;学会访问具体元素;判断元素是否存在;元素求和、求标准值、方差、去重、删除、排序...
DataFrame结构 每一列都属于Series类型,不同列之间数据类型可以不一样,但同一列的值类型必须一致。 DataFrame拥有一个总的 idx记录列,该列记录了每一行的索引 在DataFrame中,若列之间的元素个数不匹配,且使用Series填充时,在DataFrame里空值会显示为NaN;当列之间元素个数不匹配,并且不使用Series填充,会报错。在指定了index 属性显示情况下,会按照index的位置进行排序,默认是 [0,1,2,3,...] 从0索引开始正序排序行。
60 0
|
14天前
|
传感器 运维 前端开发
Python离群值检测实战:使用distfit库实现基于分布拟合的异常检测
本文解析异常(anomaly)与新颖性(novelty)检测的本质差异,结合distfit库演示基于概率密度拟合的单变量无监督异常检测方法,涵盖全局、上下文与集体离群值识别,助力构建高可解释性模型。
190 10
Python离群值检测实战:使用distfit库实现基于分布拟合的异常检测
|
7月前
|
运维 监控 算法
时间序列异常检测:MSET-SPRT组合方法的原理和Python代码实现
MSET-SPRT是一种结合多元状态估计技术(MSET)与序贯概率比检验(SPRT)的混合框架,专为高维度、强关联数据流的异常检测设计。MSET通过历史数据建模估计系统预期状态,SPRT基于统计推断判定偏差显著性,二者协同实现精准高效的异常识别。本文以Python为例,展示其在模拟数据中的应用,证明其在工业监控、设备健康管理及网络安全等领域的可靠性与有效性。
873 13
时间序列异常检测:MSET-SPRT组合方法的原理和Python代码实现
|
3月前
|
监控 编译器 Python
如何利用Python杀进程并保持驻留后台检测
本教程介绍如何使用Python编写进程监控与杀进程脚本,结合psutil库实现后台驻留、定时检测并强制终止指定进程。内容涵盖基础杀进程、多进程处理、自动退出机制、管理员权限启动及图形界面设计,并提供将脚本打包为exe的方法,适用于需持续清理顽固进程的场景。
|
9月前
|
监控 网络安全 开发者
Python中的Paramiko与FTP文件夹及文件检测技巧
通过使用 Paramiko 和 FTP 库,开发者可以方便地检测远程服务器上的文件和文件夹是否存在。Paramiko 提供了通过 SSH 协议进行远程文件管理的能力,而 `ftplib` 则提供了通过 FTP 协议进行文件传输和管理的功能。通过理解和应用这些工具,您可以更加高效地管理和监控远程服务器上的文件系统。
268 20
|
12月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
使用Python实现深度学习模型:智能质量检测与控制
使用Python实现深度学习模型:智能质量检测与控制 【10月更文挑战第8天】
765 62
使用Python实现深度学习模型:智能质量检测与控制
|
8月前
|
监控 Java 计算机视觉
Python图像处理中的内存泄漏问题:原因、检测与解决方案
在Python图像处理中,内存泄漏是常见问题,尤其在处理大图像时。本文探讨了内存泄漏的原因(如大图像数据、循环引用、外部库使用等),并介绍了检测工具(如memory_profiler、objgraph、tracemalloc)和解决方法(如显式释放资源、避免循环引用、选择良好内存管理的库)。通过具体代码示例,帮助开发者有效应对内存泄漏挑战。
373 1
|
9月前
|
数据挖掘 数据处理 开发者
Python3 自定义排序详解:方法与示例
Python的排序功能强大且灵活,主要通过`sorted()`函数和列表的`sort()`方法实现。两者均支持`key`参数自定义排序规则。本文详细介绍了基础排序、按字符串长度或元组元素排序、降序排序、多条件排序及使用`lambda`表达式和`functools.cmp_to_key`进行复杂排序。通过示例展示了如何对简单数据类型、字典、类对象及复杂数据结构(如列车信息)进行排序。掌握这些技巧可以显著提升数据处理能力,为编程提供更强大的支持。
387 10
|
9月前
|
XML 机器学习/深度学习 人工智能
使用 OpenCV 和 Python 轻松实现人脸检测
本文介绍如何使用OpenCV和Python实现人脸检测。首先,确保安装了OpenCV库并加载预训练的Haar特征模型。接着,通过读取图像或视频帧,将其转换为灰度图并使用`detectMultiScale`方法进行人脸检测。检测到的人脸用矩形框标出并显示。优化方法包括调整参数、多尺度检测及使用更先进模型。人脸检测是计算机视觉的基础技术,具有广泛应用前景。
361 10
|
12月前
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
514 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题

推荐镜像

更多