当前位置: 首页 > news >正文

代码随想录第43天:图论4(最小生成树、拓扑排序)

一、冗余的边II(Kamacoder 109)

from collections import defaultdict# 并查集 - 查找根节点(路径压缩)
def find(fa, x):if fa[x] != x:fa[x] = find(fa, fa[x])return fa[x]# 并查集 - 合并两个集合,返回是否合并成功
def union(fa, x, y):fx, fy = find(fa, x), find(fa, y)if fx != fy:fa[fx] = fyreturn True  # 合并成功,无环return False  # 已在一个集合中,成环# 判断删除某一条边后,是否构成有向树(无环)
def is_tree_after_removal(edges, remove_idx, n):fa = list(range(n + 1))  # 初始化并查集for i, (u, v) in enumerate(edges):if i == remove_idx:  # 跳过指定要删除的边continueif not union(fa, u, v):  # 出现环return Falsereturn True# 主函数:找出多余的那条边
def find_redundant_directed_connection(n, edges):in_deg = defaultdict(list)  # 记录每个节点的入边索引(用于找入度为2的点)for i, (u, v) in enumerate(edges):in_deg[v].append(i)# 情况 1:存在某个点入度为 2(有两个父节点)for v in in_deg:if len(in_deg[v]) == 2:i1, i2 = in_deg[v]# 优先删除后添加的边(尝试是否能变成树)if is_tree_after_removal(edges, i2, n):return edges[i2]# 否则只能删另一条return edges[i1]# 情况 2:无入度为2的点,仅存在有向环fa = list(range(n + 1))  # 初始化并查集for u, v in edges:if not union(fa, u, v):  # 出现环return [u, v]# 读取输入和输出结果
if __name__ == "__main__":n = int(input())  # 节点数edges = [list(map(int, input().split())) for _ in range(n)]  # 读取边print(*find_redundant_directed_connection(n, edges))  # 输出多余的那条边

二、寻宝(Kamacoder 53)

最小生成树:在无向图中求一棵树(n-1条边,无环,连通所有点),而且这棵树的边权和最小。

等价于:怎么花最小成本连通无向图的所有点???

Prim(普里姆算法):更适合稠密图,与边的数量没关系,加点法

Kruskal(克鲁斯卡尔算法):更适合稀疏图,与节点的数量没关系,加边法

最小生成树可能不唯一,但是边权和唯一!!!!

# 接收输入:v 个顶点,e 条边
v, e = list(map(int, input().strip().split()))# 使用邻接矩阵初始化图:默认所有节点之间不可达,设为一个很大的数(10001)
graph = [[10001] * (v + 1) for _ in range(v + 1)]
for _ in range(e):x, y, w = list(map(int, input().strip().split()))graph[x][y] = wgraph[y][x] = w  # 因为是无向图,双向赋值# 初始化 Prim 算法所需变量
visited = [False] * (v + 1)  # 标记哪些节点已加入生成树
minDist = [10001] * (v + 1)  # 记录每个节点与当前生成树的最短连接边权重# 从第一个节点开始构建 MST(通常默认从顶点1开始)
minDist[1] = 0  # 起点到自己权重为 0# Prim 主循环:重复选择 v 次,每次选择一个未加入树的、距离最小的节点
for _ in range(1, v + 1):min_val = 10002  # 当前最小权重(初始为无穷大)cur = -1         # 当前选择加入树的节点# 遍历所有未访问的节点,选出与树连接距离最小的那个for j in range(1, v + 1):if not visited[j] and minDist[j] < min_val:cur = jmin_val = minDist[j]visited[cur] = True  # 标记该节点已加入 MST# 更新其他未加入节点的 minDist,如果通过新加入的 cur 更近for j in range(1, v + 1):if not visited[j] and graph[cur][j] < minDist[j]:minDist[j] = graph[cur][j]# 累加所有边权(minDist[1] 是起点设为 0,可以忽略)
ans = sum(minDist[2:])  # minDist[1] 为起点设为 0,不计入答案
print(ans)

三、软件构建(Kamacoder 117)

拓扑排序:所有点按照先后顺序排成序列,每次选入度为0的点,然后删除这个点和它的出边,如果拓扑排序进行不下去了,说明图中有环。

from collections import deque, defaultdictdef topo_sort(n, edges):indeg = [0] * n  # indeg[i] 表示点 i 的入度(被多少个点指向)graph = defaultdict(list)  # 用邻接表 graph 存储有向图,graph[u] 里是所有从 u 出发可达的点# 构建图和入度数组for u, v in edges:graph[u].append(v)  # u 指向 vindeg[v] += 1       # v 的入度加一# 将所有入度为 0 的点入队,表示它们可以首先被处理q = deque(i for i in range(n) if indeg[i] == 0)res = []  # 存储拓扑排序的结果while q:u = q.popleft()   # 取出一个入度为 0 的点res.append(u)     # 加入结果中for v in graph[u]:  # 遍历 u 指向的所有节点indeg[v] -= 1   # u 被处理了,v 的入度减一if indeg[v] == 0:  # 若 v 入度减为 0,加入队列等待处理q.append(v)# 若结果中包含了所有 n 个节点,说明成功排序;否则图中有环,无法拓扑排序print(" ".join(map(str, res)) if len(res) == n else -1)if __name__ == "__main__":# 读取顶点数 n 和边数 mn, m = map(int, input().split())# 读取 m 条边,构建边列表edges = [tuple(map(int, input().split())) for _ in range(m)]# 调用拓扑排序函数topo_sort(n, edges)
http://www.xdnf.cn/news/635671.html

相关文章:

  • python学习打卡day36
  • 【node.js】node.js 安装详细步骤教程【安装在D盘】
  • Vite 构建原理 的深度解析
  • Vue3 + TypeScript + el-input 实现人民币金额的输入和显示
  • react 脚手架
  • mysql数据库之备份
  • 前端的core-js是什么?有什么作用?
  • 基于javaweb的SpringBoot体检管理系统设计与实现(源码+文档+部署讲解)
  • #RabbitMQ# 消息队列入门
  • 嵌入式预处理链接脚本lds和map文件
  • ​​IIS文件上传漏洞绕过:深入解析与高效防御​
  • MySQL索引失效的12种场景及解决方案
  • 深入理解 Linux 的 set、env 和 printenv 命令
  • ZLG USBCANFD python UDS刷写脚本
  • Nature图形解析与绘制—热图的绘制及深入解析
  • React整合【ECharts】教程002:折线图的构建和基本设置
  • 初学Transformer架构和注意力机制
  • OpenCV 第7课 图像处理之平滑(二)
  • QML与C++交互2
  • 历年哈尔滨工业大学保研上机真题
  • uni-app学习笔记十二-vue3中组件传值(对象传值)
  • urdf文件和DH模型参数是一一对应的吗??
  • 在Windows平台基于VSCode准备GO的编译环境
  • Linux基本指令篇 —— whoami指令
  • JavaScript 中 console.log() 使用逗号和加号的区别
  • C++多态与虚函数详解:从入门到精通
  • 27. 自动化测试开发框架拓展之测试数据构造(一)
  • uniapp-商城-68-shop(1-商品列表,获取数据,utils、tofixed 、parseInt的使用)
  • 【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter2 小程序核心
  • STM32八股【11】-----Linux Bootloader (U-Boot)