代码随想录算法训练营Day64|拓扑排序(卡码网117)、dijkstra朴素版

拓扑排序

117. 软件构建 (kamacoder.com)

拓扑排序简单的说是将一个有向图转为线性的排序

它将图中的所有结点排序成一个线性序列,使得对于任何的边uv,结点u在序列中都出现在结点v之前,这样的序列满足图中所有的前驱-后继关系。

拓扑排序通常用于任务调度、项目计划、编译依赖分析等场景,其中活动或任务之间存在依赖关系,需要确定一个合理的执行顺序。

拓扑排序的算法步骤如下:

  1. 选择一个没有前驱的结点(即入度为0的结点),将其加入到拓扑排序的序列中,并从图中删除该节点及其所有出边。
  2. 重复步骤1,直到所有的结点都被加入拓扑排序序列中或者途中不再存在无前驱的结点。
  3. 如果所有的结点都被加入序列中,则完成了拓扑排序;若图中还存在结点,则说明图中存在环,无法进行拓扑排序。

        由于拓扑排序的结果可能不唯一,当图中存在多个入度为0的结点,可以任意选择一个结点进行删除

在实际应用中,拓扑排序通常和深度优先搜索或广度优先搜素结合使用。例如,使用广度优先搜索(拓扑排序的广度优先搜索实现通常被称为Kahn算法)进行拓扑排序的算法流程如下:

  1. 计算所有节点的入度:遍历图中的所有节点,计算每个节点的入度(即有多少边指向该节点)。

  2. 初始化队列:创建一个空队列,将所有入度为0的节点加入队列。这些节点是没有前置依赖的节点,可以开始执行。

  3. 处理队列:只要队列不为空,就重复以下步骤:

    • 从队列中取出一个节点(称为当前节点),并将其添加到拓扑排序的结果序列中。
    • 减少当前节点的所有出边指向的节点的入度(因为这些节点的依赖减少了)。
    • 如果某个节点的入度在减少后变为0,则将其加入队列,因为它现在没有前置依赖了。
  4. 检查是否有未处理的节点:当队列为空时,如果所有的节点都已经添加到拓扑排序的结果序列中,则拓扑排序成功完成。如果还有节点未添加到结果序列中,则说明图中存在环,因此无法进行拓扑排序。

伪代码

拓扑排序(图 G):初始化入度为0的队列 Q初始化拓扑排序的结果序列 L// 计算所有节点的入度对于每个节点 v in G:v.入度 = G 中指向 v 的边的数量如果 v.入度 == 0:Q.enqueue(v)// 处理队列当 Q 不为空时:当前节点 u = Q.dequeue()L.add(u)  // 将 u 添加到拓扑排序的结果序列中// 减少所有出边的目标节点的入度对于每个节点 v,其中存在边 u -> v:v.入度 = v.入度 - 1如果 v.入度 == 0:Q.enqueue(v)// 检查是否所有节点都已处理如果 L 中的节点数量不等于 G 中的节点数量:返回 "图 G 包含环,无法进行拓扑排序"否则:返回 L 作为拓扑排序的结果序列

C++代码参考代码随想录代码随想录 (programmercarl.com)

#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;int main() {int N, M; // N个文件存在M条依赖关系cin >> N >> M;vector<int> inDegree(N, 0); // 记录每个点的入度unordered_map<int, vector<int>> umap;// 读取M条依赖关系for (int i = 0; i < M; i++) {int s, t;cin >> s >> t;// t依赖于s,因此t的入度加1inDegree[t]++;umap[s].push_back(t);}queue<int> Queue;// 将所有入度为0的节点加入队列for (int i = 0; i < N; i++) {if (inDegree[i] == 0)Queue.push(i);}vector<int> path; // 存储拓扑排序结果while (!Queue.empty()) {int cur = Queue.front();Queue.pop();path.push_back(cur);// 遍历当前节点的所有后继节点for (int next : umap[cur]) {inDegree[next]--;if (inDegree[next] == 0)Queue.push(next);}}// 检查是否所有的节点都被处理了if (path.size() == N) {for (int i = 0; i < N - 1; i++) {cout << path[i] << " ";}cout << path[N - 1];} else {// 如果不是所有的节点都被处理,说明存在环cout << -1 << endl;}return 0;
}

在时间复杂度上,初始化入度数组O(N),读取依赖关系并构建邻接表O(M)(M条依赖关系),将入度为0结点加入队列,O(N),BFS的时间复杂度为O(N+M)(每个结点最多访问一次,每个结点被加入队列后移除,每条边会被访问一次来减少相邻结点的入度)时间复杂度为O(N+M)

空间复杂度 入度数组O(N),邻接表最差情况下O(N^2),队列和路径数组都为O(N),最差情况下空间复杂度为O(N^2),但实际应用中,若图比较稀疏,则空间复杂度为O(M+N)。

dijkstra

47. 参加科学大会(第六期模拟笔试) (kamacoder.com)

        Dijkatra算法是一种著名的图搜索算法,它用于在加权图中找到从一源节点到其余所有结点的最短路径。

算法步骤:

  1. 初始化:需要一个最短路径估计的容器(优先队列,通常是最小堆)存储所有结点及其当前的最短路径估计值,除源节点设置为0外,将所有结点的最短路径估计值设置为无穷大。
  2. 访问源结点:将源结点加入优先队列。
  3. 循环处理队列:当优先队列非空时,重复以下步骤:

    从优先队列中取出具有最小估计值的节点,称为当前节点

    对于当前节点的每个邻接节点,执行以下操作:

    1. 计算通过当前节点到达邻接节点的路径长度。
    2. 如果这个路径长度比已知的最短路径估计值更短,则更新邻接节点的最短路径估计值,并更新它的前驱节点为当前节点。
    3. 将邻接节点及其新的最短路径估计值加入优先队列。 
  4. 标记完成:当一个结点从优先队列取出时,意味着它的最短路径已经确定,可以将其标记为完成。
  5. 构建最短路径树:当算法结束时,可以从源结点开始,通过每个结点的前驱结点信息,构造出从源结点到所有其他结点的最短路径树。

需要注意的几个点:

  • Dijkstra算法不能处理带有负权边的图,因为在有负权边的图中,可能存在一条路径,其总权重随着经过的边数增加而减少,导致无法正确找到最短路径。
  • Dijkstra算法的时间复杂度为O(V^2),V为图中结点的数量,使用优先队列可以优化到O(E+VlogV),E为边的数量、
  • Dijkstra可以用于有向图和无向图。

代码随想录 (programmercarl.com)

#include <iostream>
#include <vector>
#include <climits>
using namespace std;int main() {int N, M; // N个文件存在M条依赖关系cin >> N >> M;vector<vector<int>> grid(N+1, vector<int>(N+1, INT_MAX)); // 创建一个N+1xN+1的二维数组,用于存储节点之间的权重,初始化为INT_MAXint v1, v2, val;for (int i = 0; i < M; i++) { // 读取M条依赖关系cin >> v1 >> v2 >> val; // 读取两个节点v1和v2以及它们之间的权重valgrid[v1][v2] = val; // 更新权重矩阵,表示v1到v2有边,权重为val}int start = 1; // 定义起始节点为1int end = N; // 定义目标节点为Nvector<int> minDist(N+1, INT_MAX); // 创建一个长度为N+1的数组,用于存储从起始节点到其他节点的最短路径估计值,初始化为INT_MAXvector<int> visited(N+1, 0); // 创建一个长度为N+1的数组,用于标记节点是否被访问过,0表示未访问,1表示已访问minDist[start] = 0; // 起始节点到自身的最短路径为0for (int i = 0; i <= N; i++) { // 循环,找到未访问的最短路径节点int minVal = INT_MAX; // 初始化最小值为INT_MAXint cur = 1; // 初始化当前节点为1for (int v = 1; v <= N; v++) { // 遍历所有节点,找到未访问且最短路径估计值最小的节点if (!visited[v] && minDist[v] < minVal) { // 如果节点v未访问且最短路径估计值小于minValminVal = minDist[v]; // 更新最小值cur = v; // 更新当前节点为v}}visited[cur] = 1; // 标记当前节点为已访问for (int v = 1; v <= N; v++) { // 遍历所有节点,更新从当前节点出发到其他节点的最短路径估计值if (!visited[v] && grid[cur][v] != INT_MAX && minDist[cur] + grid[cur][v] < minDist[v]) {// 如果节点v未访问,且当前节点到节点v有边,且通过当前节点到达v的路径更短minDist[v] = minDist[cur] + grid[cur][v]; // 更新节点v的最短路径估计值}}}if (minDist[end] == INT_MAX) // 如果目标节点的最短路径估计值仍然是INT_MAX,表示没有路径到达目标节点cout << -1 << endl; // 输出-1elsecout << minDist[end] << endl; // 否则输出从起始节点到目标节点的最短路径长度return 0;
}

算法的时间复杂度为O(N^2),空间复杂度这里也是O(N^2)(没有用上最小堆等优先队列)

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

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

相关文章

vue 插槽 【slot】

文章目录 默认插槽具名插槽作用域插槽 默认插槽 父组件中&#xff1a;<Category title"今日热门游戏"><ul><li v-for"g in games" :key"g.id">{{ g.name }}</li></ul></Category> 子组件中&#xff1a;<…

9. 机器人数目

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 少年宫新近邮购了小机器人配件&#xff0c;共有3类。 &#x1d434;A 类含有&#xff1a;88 个轮子&#xff0c;11 个传感器&#xff1b; &#x1d435;B 类含有:…

深入理解基本数据结构:栈详解

引言 在计算机科学中&#xff0c;数据结构是存储、组织和管理数据的方式。栈是一种重要的线性数据结构&#xff0c;广泛应用于各种编程场景。在这篇博客中&#xff0c;我们将详细探讨栈的定义、特点、操作及其在不同编程语言中的实现。 什么是栈&#xff1f; **栈&#xff08…

java动态代理的使用和代码示例

文章目录 1. 简介2. 代码3. 参考链接 1. 简介 代理类在程序运行时创建的代理方式被成为动态代理。在静态代理中&#xff0c;代理类&#xff08;RenterProxy&#xff09;是自己已经定义好了的&#xff0c;在程序运行之前就已经编译完成。而动态代理是在运行时根据我们在Java代码…

前端vue 实现取色板 的选择

大概就是这样的 一般的web端框架 都有自带的 的 比如 ant-design t-design 等 前端框架 都是带有这个的 如果遇到没有的我们可以自己尝试开发一下 简单 的 肯定比不上人家的 但是能用 能看 说的过去 我直接上代码了 其实这个取色板 就是一个input type 是color 的input …

CTF学习记录(一)——Web基础

目录 Web基础Web基础常用工具ncat(网络工具中的瑞士军刀&#xff0c;功能齐全)curl(一个工作在命令行的发起HTTP请求的工具)BurpSuite(Web核心抓包工具)Hackbar插件SwitchyOmega 代理插件&#xff08;非常牛逼&#xff09;Wappalyzer 技术判断插件EditThisCookie 插件Postman 接…

深入理解Spring Boot中的定时任务调度

深入理解Spring Boot中的定时任务调度 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. Spring Boot中的定时任务概述 在现代应用程序开发中&#xff0c;定时任务调度是一项非常常见和重要的功能…

【计算机网络03】不花钱怎么搭建一个网络实验室

使用GNS3和虚拟机搭建网络实验室 1、安装抓包工具分析数据包2、定义和使用抓包筛选器3、安装和配置GNS34、配置路由器和VPCS5、使用WireShark捕获GNS3网络数据包6、VMware创建虚拟机7、使用思科PacketTracer 1、安装抓包工具分析数据包 官网安装wireshark&#xff1a;https://…

python怎么判断字符串以什么结尾

在python编辑器中新建一个data.py。 写上自己的注释。 然后新建一个变量testname。 利用endswith来判断字符串是不是以“ar”结尾。 将结果打印出来。 选择“run”->“run”。 运行该程序&#xff0c;如果是&#xff0c;就会返回true。

JavaScript-日期对象

日期对象 作用&#xff1a;用来表示时间的对象 获取当前时间 const datenew Date();console.log(date);可以得到日期对象&#xff0c;里面的属性有星期&#xff0c;年月日&#xff0c;时分秒 获取指定时间 const datenew Date(2023-05-01);console.log(date); 获取时间戳 时间…

PyTorch深度学习实战(45)——强化学习

PyTorch深度学习实战&#xff08;45&#xff09;——强化学习 0. 前言1. 强化学习基础1.1 基本概念1.2 马尔科夫决策过程1.3 目标函数1.4 智能体学习过程 2. 计算状态值3. 计算状态-动作值4. Q 学习4.1 Q 值4.2 Gym环境4.3 构建 Q 表4.4 探索-利用策略 小结系列链接 0. 前言 强…

悠律凝声环开放式耳机体验:强劲低音、高颜值设计

最近发现了一款潮酷的开放式耳机&#xff0c;不仅颜值抗打&#xff0c;更重要的是能在嘈杂的环境中提供给我一份宁静的沉浸式音乐体验&#xff0c;号称是开放音频中的重低音之王&#xff0c;它就是悠律凝声环开放式耳机。 这款耳机无论其外观设计、音质效果、性价比以及续航能力…

通勤数据:Comma2k19 数据集

A Commute in Data: The comma2k19 Dataset 通勤数据&#xff1a;Comma2k19 数据集 https://arxiv.org/pdf/1812.05752v1 Abstract— comma.ai presents comma2k19, a dataset of over 33 hours of commute in California’s 280 highway. This means 2019 segments, 1 minut…

js实现寻找数组中满足某个条件的对象,以及找到下标后,在数组中插入某个对象

let ItemIndex fileList.findIndex((item) > { return item.xxx 你要找的属性值 }); if(ItemIndex > -1){ // 代表找到了这个元素 } else { } 参考百度AI: 在JavaScript中&#xff0c;‌可以使用splice()方法在指定位置插入一个或多个对象到数组…

npm、cnpm、pnpm、yarn的区别

npm, cnpm, pnpm, 和 yarn 都是 JavaScript 的包管理工具&#xff0c;用于自动化处理包的安装、更新、配置和管理。它们之间的主要区别在于它们各自的实现方式、性能优化、以及一些特有的功能。 npm npm (Node Package Manager) 是 Node.js 的默认包管理器&#xff0c;也是最…

「媒体邀约」上海请媒体的费用

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 上海无疑是最具活动的城市之一&#xff0c;各种大大小小的论坛、发布会、展览展会应接不暇&#xff0c;那么在上海做活动想邀请媒体进行宣传报道&#xff0c;需要多少费用呢&#xff1a;…

Android --- 运行时Fragment如何获取Activity中的数据,又如何将数据传递到Activity中呢?

1.通过 getActivity() 方法获取 Activity 实例&#xff1a; 在 Fragment 中&#xff0c;可以通过 getActivity() 方法获取当前 Fragment 所依附的 Activity 实例。然后可以调用 Activity 的公共方法或者直接访问 Activity 的字段来获取数据。 // 在 Fragment 中获取 Activity…

手慢无,速看︱PMO大会内部学习资料

全国PMO专业人士年度盛会 每届PMO大会&#xff0c;组委会都把所有演讲嘉宾的PPT印刷在了会刊里面&#xff0c;供大家会后回顾与深入学习。 第十三届中国PMO大会-会刊 《2024第十三届中国PMO大会-会刊》 &#xff08;内含演讲PPT&#xff09; 会刊&#xff1a;750个页码&…

代码随想录-DAY④-链表——leetcode 24 | 19 | 142

24 思路 如果 pre 的后面没有节点或者只有一个节点&#xff0c;则没有更多的节点需要交换, 否则&#xff0c;通过更新节点的指针关系交换 pre 后面的两个节点&#xff0c; 最后&#xff0c;返回新的链表的头节点 dummyhead->next。 时间复杂度&#xff1a;O(n) 空间复杂…

buuctf面具下的flag

细节: 这道题可能因为是vmdk的原因 导致在window上 7z无法得到全部的信息 所以最后解压要在linux系统上 解密网站 Brainfuck/Ook! Obfuscation/Encoding [splitbrain.org] 这道题010打开,可以发现里面隐藏了很多 binwalk解压 两个文件 vmdk可以直接 用7z解压 7z x flag.…