Leetcode 1489. 找到最小生成树里的关键边和伪关键边

news2024/11/29 9:37:36

1.题目基本信息

1.1.题目描述

给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。

请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。

请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。

1.2.题目地址

https://leetcode.cn/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/description/

2.解题方法

2.1.解题思路

无向图的连通性质:取权值为w的边,让小于w的边构成一个一个的连通分量comps,将每个连通分量comp作为一个节点,将w大小的节点与comps这些节点重新构建一个图,记为compG。

compG中的桥即为关键边;w大小的边的两端如果在同一个连通分量内,则既不是关键边也不是伪关键边;余下的都是伪关键边。

2.2.解题步骤

解题步骤请看代码注释

3.解题代码

Python代码

# # ==> 并查集模板(附优化)
class UnionFind():
    def __init__(self):
        self.roots={}
        self.setCnt=0   # 连通分量的个数
        # Union优化:存储根节点主导的集合的总节点数
        self.rootSizes={}
    
    def add(self,x):
        if x not in self.roots:
            self.roots[x]=x
            self.rootSizes[x]=1
            self.setCnt+=1
    
    def find(self,x):
        root=x
        while root != self.roots[root]:
            root=self.roots[root]
        # 优化:压缩路径
        while x!=root:
            temp=self.roots[x]
            self.roots[x]=root
            x=temp
        return root
    
    def union(self,x,y):
        rootx,rooty=self.find(x),self.find(y)
        if rootx!=rooty:
            # 优化:小树合并到大树上
            if self.rootSizes[rootx]<self.rootSizes[rooty]:
                self.roots[rootx]=rooty
                self.rootSizes[rooty]+=self.rootSizes[rootx]
            else:
                self.roots[rooty]=rootx
                self.rootSizes[rootx]+=self.rootSizes[rooty]
            self.setCnt-=1


from typing import List
class UndirectedGraphTarjan2():
    def __init__(self,graph:List[int:List[int]],graphEdges:List[int:List[int]]):
        self.length=len(graph)
        self.graph=graph    # 邻接表
        self.graphEdges=graphEdges  # 邻接表同结构的边
        self.dfn=[-1]*self.length
        self.low=[-1]*self.length
        self.bridges=[]
        self.timestamp=0
    
    def tarjan(self):
        for i in range(self.length):
            if self.graph[i]!=-1:
                self.tarjanDfs(i,-1)
    
    def tarjanDfs(self,node:int,fatherEdge:int):
        self.dfn[node]=self.low[node]=self.timestamp
        self.timestamp+=1
        for i in range(len(self.graph[node])):
            subNode,edge=self.graph[node][i],self.graphEdges[node][i]   # 这里边是node指向subNode的边
            if self.dfn[subNode]==-1:
                self.tarjanDfs(subNode,edge)
                self.low[node]=min(self.low[node],self.low[subNode])
                if self.dfn[node]<self.low[subNode]:
                    self.bridges.append(edge)
            elif edge!=fatherEdge:
                self.low[node]=min(self.low[node],self.low[subNode])


from collections import defaultdict
class Solution:
    def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]:
        edgesLength=len(edges)
        # 将所有的边编号并获取点->边id的映射
        for i in range(edgesLength):
            edges[i].append(i)
        # 将所有的边按权值从小到大进行排序
        edges.sort(key=lambda x:x[2])
        # 构建所有点的并查集(不用进行连接)
        uf=UnionFind()
        for i in range(n):
            uf.add(i)
        # 初始化所有边的标签为-1(1为关键边,0则两者都不是,最后还是-1的为伪关键边)
        labels=[-1]*edgesLength
        # 遍历所有的相同权值的边组edges[i,j)
        i=0
        while i<edgesLength:
            # 获取j的值
            j=i
            while j<edgesLength and edges[i][2]==edges[j][2]:
                j+=1
            # 将各个点按并查集分成m个连通分量,每个连通分量为新图compG中的一个节点,并给每个连通分量初始化需要i
            node2CompId={}
            compCnt=0
            for k in range(i,j):
                node1,node2,weight,edgeId=edges[k]
                node1Root,node2Root=uf.find(node1),uf.find(node2)
                if node1Root!=node2Root:
                    if node1Root not in node2CompId:
                        node2CompId[node1Root]=compCnt
                        compCnt+=1
                    if node2Root not in node2CompId:
                        node2CompId[node2Root]=compCnt
                        compCnt+=1
                else:
                    labels[edgeId]=0    # 改变既不是关键边,也不是伪关键边
            # print(node2CompId)
            # 构建邻接表形式的compG和对应的边的id
            compG=defaultdict(list)
            compGEids=defaultdict(list)
            for k in range(i,j):
                node1,node2,weight,edgeId=edges[k]
                node1Root,node2Root=uf.find(node1),uf.find(node2)
                if node1Root!=node2Root:
                    compId1,compId2=node2CompId[node1Root],node2CompId[node2Root]
                    compG[compId1].append(compId2)
                    compGEids[compId1].append(edgeId)
                    compG[compId2].append(compId1)
                    compGEids[compId2].append(edgeId)
            # print(compCnt, compG, compGEids)
            ugt2=UndirectedGraphTarjan2(compG, compGEids)
            ugt2.tarjan()
            bridges=ugt2.bridges
            # print("bridges",bridges)
            # 将桥标记为1
            for bridge in bridges:
                labels[bridge]=1
            # 遍历[i,j)之间的边。如果该边是compG的桥,则该边是关键边;如果该边首尾连接同一个连通分量节点,则既不是关键边,也不是伪关键边;
            for k in range(i,j):
                node1,node2,weight,edgeId=edges[k]
                uf.union(node1,node2)
            # 更新i
            i=j
        # 标记完成后,剩下的没有标记的边即为伪关键边
        # 返回结果
        # print(labels)
        result=[[],[]]
        for i in range(edgesLength):
            if labels[i]==1:
                result[0].append(i)
            elif labels[i]==-1:
                result[1].append(i)
        return result

4.执行结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

114.WEB渗透测试-信息收集-ARL(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;113.WEB渗透测试-信息收集-ARL&#xff08;4&#xff09; 输入&#xff1a; docker ps 查…

GPT和BERT

GPT和BERT都是基于Trm的应用&#xff0c;可以理解为GPT是decoder的应用&#xff0c;BERT可以说是encoder的应用 GPT 如图&#xff0c;就是GPT的原理&#xff0c;GPT是做生成式的任务的&#xff0c;没有办法进行下游任务改造&#xff0c;训练也是针对生成式的任务进行训练 BE…

【JavaEE】【IO】文件操作

目录 一、文件1.1 文件的概念1.2 文件的操作1.3 路径1.4 文件分类 二、Java中的文件元信息、路径操作2.1 属性2.2 构造方法2.3 方法2.3.1 文件路径2.3.2 文件判断2.3.3 文件创建删除2.3.4 其他操作 三、文件读写操作3.1 流&#xff08;Stream&#xff09;3.1.1 字节流3.1.1.1 I…

vmware虚拟机 报错:客户机操作系统已禁用 CPU,请关闭或重置虚拟机 的解决方法

打开cpu虚拟化全部进行勾选 ctrl e 进行关机 勾选上打开就好了 如果没有那个选项 关机>打开虚拟机>管理>更改硬件兼容性> 往小处改改> >更改此虚拟机

【干货】老师用什么小程序发布期中考试成绩?

即将迎来新学期第一次期中考试。考试结束后&#xff0c;老师们又要开始忙碌于成绩的统计和发布工作。易查分小程序就是其中一个非常实用的选择。它专为发布成绩而设计&#xff0c;能够帮助老师们轻松地完成成绩的发布工作。 通过易查分小程序&#xff0c;老师们可以快速地将成绩…

雷池社区版配置遇到问题不要慌,查看本文解决

很多新人不太熟悉反向代理&#xff0c;所以导致配置站点出现问题 配置问题 记录常见的配置问题 配置后攻击测试没有拦截记录 检查访问请求有没有真实经过雷池 有很多新人配置站点后&#xff0c;真实的网站流量还是走的源站&#xff0c;导致雷池这边什么数据都没有 配置后…

【工程测试技术】第4章 常用传感器分类,机械式,电阻式,电容式,电感式,光电式传感器

上理考研周导师的哔哩哔哩频道 我在频道里讲课哦 目录 4.1 常用传感器分类 4.2 机械式传感器及仪器 4.3 电阻式、电容式与电感式传感器 1.变阻器式传感器 2.电阻应变式传感器 3.固态压阻式传感器 4.典型动态电阻应变仪 4.3.2 电容式传感器 1.变换原理 2.测量电路 …

如何下载3GPP协议?

一、进入3GPP网页 https://www.3gpp.org/ 二、点击“Specifications &Technologies” 三、点击“FTP Server” 网址&#xff1a; https://www.3gpp.org/specifications-technologies 四、找到“latest”&#xff0c;查看最新版 网址&#xff1a; https://www.3gpp.org/ftp…

Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS通过startActivity启动Activity的整个流程的整个流程的第二阶段&#xff1a;从ActivityThread启动到Activity拉起。 第一阶段文…

【超详细】UDP协议

UDP传输层协议的一种&#xff0c;UDP(User Datagram Protocol 用户数据报协议)&#xff1a; 传输层协议无连接不可靠传输面向数据报 UDP协议端格式 定长报头&#xff0c;8字节源端口号和目的端口号来定位16位UDP长度, 表示整个数据报(UDP首部UDP数据)的最大长度如果校验和出错…

Java重修笔记 第六十七天 坦克大战(完结)

奋斗一个多月终于把坦克大战写出来了&#xff0c;看了韩老师的思路然后自己手打&#xff0c;自己做不出来就看视频然后再写&#xff0c;总结收获和难点突破点如下&#xff1a; 1. 抽象类意识 刚开始没有将 Hero 和 Enemy 抽象出顶级父类 Tank&#xff0c;看了韩老师的视频&…

存储器学习记录(资源整合)

&#xff08;一&#xff09;整合资料&#xff1a; openedv.com/thread-300792-1-1.html 需搭配的底板&#xff1a; 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 openedv.com/thread-272902-1-1.html 、、、、、、、、、、、、、、、、、、、、…

如何给4G模块(ESP32设备),ESP8266进行联网?

具体步骤&#xff1a; 1.打开uPyLoader&#xff0c;选择端口号&#xff0c;连接 连接成功后&#xff0c;点击工具栏的file-navigate&#xff0c;找到联网代码所在目录 联网代码&#xff1a; import network import timedef wifi_connect(ssid, password):wlan network.WLA…

实战篇:(三)项目实战Vue 3 + WebGL 创建一个简单的 3D 渲染应用

Vue 3 WebGL 创建一个简单的 3D 渲染应用 我们将使用 Vue 3 和 WebGL 创建一个简单的 3D 渲染应用。项目将展示如何在 Vue 组件中集成 WebGL&#xff0c;并渲染一个旋转的立方体。 1. 项目准备 首先&#xff0c;确保你已经安装了 Node.js 和 Vue CLI。如果还没有安装&#x…

一键docker脚本

#!/bin/bash ## Author: SuperManito ## Modified: 2024-10-07 ## License: MIT ## GitHub: https://github.com/SuperManito/LinuxMirrors ## Website: https://linuxmirrors.cn## Docker CE 软件源列表 # 格式&#xff1a;"软件源名称软件源地址" mirror_list_dock…

WebGl 如何给页面绑定点击事件

在WebGL中给页面绑定点击事件&#xff0c;可以通过为WebGL的绘图上下文所在的<canvas>元素添加事件监听器来实现点击事件的处理。 1. 画布添加点击事件 const ctx document.getElementById(canvas) const gl ctx.getContext(webgl)ctx.onclick function (e) {// 给ca…

深入理解WPF中的命令机制

Windows Presentation Foundation&#xff08;WPF&#xff09;是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础&#xff0c;具有强大的图形和媒体处理能力。在WPF中&#xff0c;“命令”是一个重要的概念&#xff0c;它为应用程序开发…

Ubuntu下编译opencv4.5遇到的问题及解决方法

一、编译opencv4.5的步骤 1、安装依赖项 sudo apt update sudo apt install build-essential cmake git pkg-config \ libjpeg-dev libtiff-dev libpng-dev \ libavcodec-dev libavformat-dev libswscale-dev \ libv4l-dev libxvidcore-dev libx264-dev \ libgtk-3-dev libat…

使用Arcgis批量自动出图

操作方法如下&#xff1a; 1 2 3 4 5 6 7 设置好选项&#xff0c;开始打印。 8 生成pdf。 第一步&#xff1a;shp放到数据库中&#xff0c;标注转注记&#xff0c;然后编辑注记&#xff0c;符号样式设置好。准备出图&#xff1a;&#xff08;转注记时候尽量压盖监测等选最…

使用Windows创建一个MFC应用【带界面】

MFC使用教程【对初学者保姆型友好&#xff01;】 目录 前提条件 1&#xff1a;创建MFC应用程序 2. 项目结构解读 引用 外部依赖项 头文件 源文件 资源文件 文件功能详解 项目的主要流程 步骤2&#xff1a;配置OpenCV 安装OpenCV 包含目录与库文件 步骤3&#xff1…