代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会

提示:DDU,供自己复习使用。欢迎大家前来讨论~

文章目录

  • 图论part08
    • **拓扑排序精讲**
    • 题目:117. 软件构建
    • 拓扑排序的背景
      • 解题思路:
      • 模拟过程
    • **dijkstra(朴素版)精讲**
    • 题目:47. 参加科学大会
      • 解题思路
    • 朴素版dijkstra
      • 模拟过程
    • 总结

图论part08

拓扑排序精讲

题目:117. 软件构建

117. 软件构建 (kamacoder.com)

拓扑排序的背景

拓扑排序:

  1. 图论问题:拓扑排序是图论中的一个经典问题。
  2. 应用场景:
    • 大学排课:需要按照先决条件排序课程。
    • 文件处理:在项目安装或依赖管理中处理复杂的文件依赖关系。
  3. 处理大规模依赖:适用于处理成千上万的依赖关系。
  4. 检测循环依赖:拓扑排序可以发现循环依赖,即无法进行线性排序的情况。
  5. 排序目标:将有向图中的顶点转换为线性顺序。

解题思路:

  1. 广度优先搜索(BFS):这是实现拓扑排序最常用的方法,简单易懂。
  2. 算法步骤
    • 入度表:首先构建一个入度表,记录每个顶点的入度,即指向该顶点的边的数量。
    • 队列:将所有入度为0的顶点(即没有任何顶点指向的顶点)加入队列。
    • 处理队列:当队列非空时,依次从队列中取出一个顶点,加入到拓扑排序的结果序列中,并减少与该顶点相邻的顶点的入度。如果相邻顶点的入度变为0,也将它们加入队列。
    • 重复:重复上述过程,直到队列为空。
    • 检测环:如果结果序列中的顶点数小于图中顶点的总数,说明图中存在环,无法进行拓扑排序。
  3. 深度优先搜索(DFS):另一种实现拓扑排序的方法,但不是本篇的重点。
  4. 卡恩算法:1962年提出的拓扑排序算法,基于BFS。
  5. 核心思想:拓扑排序的核心思想是将有向无环图中的顶点进行线性排序,同时检测图中是否存在环。

拓扑排序的简单理解:

  1. 找起点:先找到所有没有任何前置条件(入度为0)的节点。

  2. 加入结果:把这些节点加入到一个结果列表中。

  3. 移除节点:从图中删除这些节点,以及它们指向的所有边。

  4. 重复:重复以上步骤,直到找不到入度为0的节点。

  5. 检测环:如果最后结果列表中的节点数和图中的节点数不一样,说明有环,无法完成排序。

  6. 输出:如果能找到完整的排序,就输出结果列表;否则,说明存在环,输出错误信息。

拓扑排序就是按照一定的顺序,把图中的节点排成一行,同时确保所有的依赖关系都得到满足。如果排不出这样的顺序,就说明图中有环,存在无法解决的依赖关系。

模拟过程

假设我们有以下的任务依赖关系:

A -> C
A -> D
B -> C
C -> D

这意味着:

  • 要执行任务C,必须先执行任务A。
  • 要执行任务D,必须先执行任务A和C。
  • 要执行任务C,必须先执行任务B。

我们来模拟拓扑排序的步骤:

步骤1:初始化

  • 入度:A=0, B=0, C=2(A->C, B->C), D=2(A->D, C->D)
  • 依赖关系:A->(C, D), B->©, C->(D)
  • 结果集:()

步骤2:找到入度为0的节点

  • A和B的入度都为0,我们可以选择A或B作为起点。这里我们选择A。

步骤3:加入结果集并移除节点

  • 结果集变为:(A)
  • 移除A及其依赖关系,更新入度:
    • 移除A后,C的入度变为1(只剩B->C),D的入度变为1(只剩C->D)。

步骤4:重复步骤2

  • 接下来,我们再次找入度为0的节点,现在B的入度为0。

步骤5:加入结果集并移除节点

  • 结果集变为:(A, B)
  • 移除B及其依赖关系,更新入度:
    • 移除B后,C的入度变为0。

步骤6:重复步骤2

  • 现在C的入度为0。

步骤7:加入结果集并移除节点

  • 结果集变为:(A, B, C)
  • 移除C及其依赖关系,更新入度:
    • 移除C后,D的入度变为0。

步骤8:重复步骤2

  • 最后,D的入度为0。

步骤9:加入结果集

  • 结果集变为:(A, B, C, D)

步骤10:检测环

  • 结果集的节点数等于图中的节点数,说明没有环,我们可以完成排序。

最终结果:(A, B, C, D)

这个顺序告诉我们,为了满足所有依赖关系,我们可以先执行A,然后执行B,接着执行C,最后执行D。

如果在这个过程中,我们发现无法再找到入度为0的节点,但结果集中的节点数小于图中节点的总数,那么我们可以确定图中存在环,无法进行拓扑排序。

最后代码如下:

#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
int main() {
    int m, n, s, t;
    cin >> n >> m;
    vector<int> inDegree(n, 0); // 记录每个文件的入度

    unordered_map<int, vector<int>> umap;// 记录文件依赖关系
    vector<int> result; // 记录结果

    while (m--) {
        // s->t,先有s才能有t
        cin >> s >> t;
        inDegree[t]++; // t的入度加一
        umap[s].push_back(t); // 记录s指向哪些文件
    }
    queue<int> que;
    for (int i = 0; i < n; i++) {
        // 入度为0的文件,可以作为开头,先加入队列
        if (inDegree[i] == 0) que.push(i);
        //cout << inDegree[i] << endl;
    }
    // int count = 0;
    while (que.size()) {
        int  cur = que.front(); // 当前选中的文件
        que.pop();
        //count++;
        result.push_back(cur);
        vector<int> files = umap[cur]; //获取该文件指向的文件
        if (files.size()) { // cur有后续文件
            for (int i = 0; i < files.size(); i++) {
                inDegree[files[i]] --; // cur的指向的文件入度-1
                if(inDegree[files[i]] == 0) que.push(files[i]);
            }
        }
    }
    if (result.size() == n) {
        for (int i = 0; i < n - 1; i++) cout << result[i] << " ";
        cout << result[n - 1];
    } else cout << -1 << endl;


}

dijkstra(朴素版)精讲

题目:47. 参加科学大会

[47. 参加科学大会(第六期模拟笔试) (kamacoder.com)](https://kamacoder.com/problempage.php?pid=1053)

解题思路

  1. 最短路径问题:在有向图中,给定一个起点和一个终点,求出从起点到终点的最短路径。
  2. Dijkstra算法:一种用于在有权图中找到从单个源点到所有其他节点的最短路径的算法。这里的权值是非负数。
  3. Dijkstra算法的特点
    • 可以同时求出源点到所有其他节点的最短路径。
    • 权值不能为负数。
  4. 算法思路:Dijkstra算法采用贪心策略,不断寻找距离源点最近的未访问节点。
  5. Dijkstra算法的三部曲
    • 第一步:选择源点到最近且未被访问过的节点。
    • 第二步:将这个最近节点标记为已访问。
    • 第三步:更新非访问节点到源点的距离。
  6. 与Prim算法的比较:Dijkstra算法和Prim算法在思路上非常相似,都是贪心算法,但Prim算法用于最小生成树问题。
  7. minDist数组:在Dijkstra算法中,minDist数组用于记录每个节点到源点的最小距离,这是理解算法的核心。
  8. 算法演示:通过画图的方式展示了Dijkstra算法的工作过程,帮助理解算法是如何逐步找到最短路径的。

朴素版dijkstra

模拟过程


0、初始化

minDist数组数值初始化为int最大值。

这里在强点一下 minDist数组的含义:记录所有节点到源点的最短路径,那么初始化的时候就应该初始为最大值,这样才能在后续出现最短路径的时候及时更新。

img

(图中,max 表示默认值,节点0 不做处理,统一从下标1 开始计算,这样下标和节点数值统一, 方便大家理解,避免搞混)

源点(节点1) 到自己的距离为0,所以 minDist[1] = 0

此时所有节点都没有被访问过,所以 visited数组都为0


以下为dijkstra 三部曲

1、选源点到哪个节点近且该节点未被访问过

源点距离源点最近,距离为0,且未被访问。

2、该最近节点被标记访问过

标记源点访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

更新 minDist数组,即:源点(节点1) 到 节点2 和 节点3的距离。

  • 源点到节点2的最短距离为1,小于原minDist[2]的数值max,更新minDist[2] = 1
  • 源点到节点3的最短距离为4,小于原minDist[3]的数值max,更新minDist[3] = 4

可能有录友问:为啥和 minDist[2] 比较?

再强调一下 minDist[2] 的含义,它表示源点到节点2的最短距离,那么目前我们得到了 源点到节点2的最短距离为1,小于默认值max,所以更新。 minDist[3]的更新同理


1、选源点到哪个节点近且该节点未被访问过

未访问过的节点中,源点到节点2距离最近,选节点2

2、该最近节点被标记访问过

节点2被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

更新 minDist数组,即:源点(节点1) 到 节点6 、 节点3 和 节点4的距离。

为什么更新这些节点呢? 怎么不更新其他节点呢

因为 源点(节点1)通过 已经计算过的节点(节点2) 可以链接到的节点 有 节点3,节点4和节点6.

更新 minDist数组:

  • 源点到节点6的最短距离为5,小于原minDist[6]的数值max,更新minDist[6] = 5
  • 源点到节点3的最短距离为3,小于原minDist[3]的数值4,更新minDist[3] = 3
  • 源点到节点4的最短距离为6,小于原minDist[4]的数值max,更新minDist[4] = 6

1、选源点到哪个节点近且该节点未被访问过

未访问过的节点中,源点距离哪些节点最近,怎么算的?

其实就是看 minDist数组里的数值,minDist 记录了 源点到所有节点的最近距离,结合visited数组筛选出未访问的节点就好。

从 上面的图,或者 从minDist数组中,我们都能看出 未访问过的节点中,源点(节点1)到节点3距离最近。

2、该最近节点被标记访问过

节点3被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

由于节点3的加入,那么源点可以有新的路径链接到节点4 所以更新minDist数组:

更新 minDist数组:

  • 源点到节点4的最短距离为5,小于原minDist[4]的数值6,更新minDist[4] = 5

1、选源点到哪个节点近且该节点未被访问过

距离源点最近且没有被访问过的节点,有节点4 和 节点6,距离源点距离都是 5 (minDist[4] = 5,minDist[6] = 5) ,选哪个节点都可以。

2、该最近节点被标记访问过

节点4被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

由于节点4的加入,那么源点可以链接到节点5 所以更新minDist数组:

  • 源点到节点5的最短距离为8,小于原minDist[5]的数值max,更新minDist[5] = 8

1、选源点到哪个节点近且该节点未被访问过

距离源点最近且没有被访问过的节点,是节点6,距离源点距离是 5 (minDist[6] = 5)

2、该最近节点被标记访问过

节点6 被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

由于节点6的加入,那么源点可以链接到节点7 所以 更新minDist数组:

  • 源点到节点7的最短距离为14,小于原minDist[7]的数值max,更新minDist[7] = 14

1、选源点到哪个节点近且该节点未被访问过

距离源点最近且没有被访问过的节点,是节点5,距离源点距离是 8 (minDist[5] = 8)

2、该最近节点被标记访问过

节点5 被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

由于节点5的加入,那么源点有新的路径可以链接到节点7 所以 更新minDist数组:

  • 源点到节点7的最短距离为12,小于原minDist[7]的数值14,更新minDist[7] = 12

1、选源点到哪个节点近且该节点未被访问过

距离源点最近且没有被访问过的节点,是节点7(终点),距离源点距离是 12 (minDist[7] = 12)

2、该最近节点被标记访问过

节点7 被标记访问过

3、更新非访问节点到源点的距离(即更新minDist数组) ,如图:

img

节点7加入,但节点7到节点7的距离为0,所以 不用更新minDist数组


最后我们要求起点(节点1) 到终点 (节点7)的距离。

再来回顾一下minDist数组的含义:记录 每一个节点距离源点的最小距离。

那么起到(节点1)到终点(节点7)的最短距离就是 minDist[7] ,按上面举例讲解来说,minDist[7] = 12,节点1 到节点7的最短路径为 12。

路径如图:

img

在上面的讲解中,每一步 我都是按照 dijkstra 三部曲来讲解的,理解了这三部曲,代码也就好懂的。

本题代码如下:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;

    vector<vector<int>> grid(n + 1, vector<int>(n + 1, INT_MAX));
    for(int i = 0; i < m; i++){
        cin >> p1 >> p2 >> val;
        grid[p1][p2] = val;
    }

    int start = 1;
    int end = n;

    // 存储从源点到每个节点的最短距离
    std::vector<int> minDist(n + 1, INT_MAX);

    // 记录顶点是否被访问过
    std::vector<bool> visited(n + 1, false);

    minDist[start] = 0;  // 起始点到自身的距离为0

    for (int i = 1; i <= n; i++) { // 遍历所有节点

        int minVal = INT_MAX;
        int cur = 1;

        // 1、选距离源点最近且未访问过的节点
        for (int v = 1; v <= n; ++v) {
            if (!visited[v] && minDist[v] < minVal) {
                minVal = minDist[v];
                cur = v;
            }
        }

        visited[cur] = true;  // 2、标记该节点已被访问

        // 3、第三步,更新非访问节点到源点的距离(即更新minDist数组)
        for (int v = 1; v <= n; v++) {
            if (!visited[v] && grid[cur][v] != INT_MAX && minDist[cur] + grid[cur][v] < minDist[v]) {
                minDist[v] = minDist[cur] + grid[cur][v];
            }
        }

    }

    if (minDist[end] == INT_MAX) cout << -1 << endl; // 不能到达终点
    else cout << minDist[end] << endl; // 到达终点最短路径

}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2)

总结

拓扑排序精讲
拓扑排序是针对有向无环图(DAG)的一种排序算法,目的是将图中的所有顶点排成一个线性序列,使得对于任何一条有向边(U \rightarrow V),顶点(U)都在顶点(V)的前面。这个过程可以用来检测图中是否存在环,因为如果无法完成排序,则说明图中有环。拓扑排序的关键在于每次选择入度为0的顶点加入排序结果,并更新相关顶点的入度。

Dijkstra(朴素版)精讲
Dijkstra算法是一种计算单源最短路径的算法,适用于边权重为非负数的图。它通过维护一个距离数组,记录源点到所有其他顶点的已知最短距离,然后不断更新这个距离数组来找到最短路径。朴素版的Dijkstra算法使用简单的循环来更新距离,没有使用优先队列,因此效率较低,但其核心思想是贪心地选择当前最短的未处理顶点,并更新其相邻顶点的距离。

拓扑排序的经典例子
假设有一个课程学习系统,其中课程间存在先修要求,比如:

  • 课程A是课程B的先修课
  • 课程B是课程C的先修课
    拓扑排序可以用来确定一个满足所有先修要求的课程学习顺序。例如,一个有效的学习顺序可能是A→B→C。

Dijkstra算法(朴素版)的经典例子
考虑一个带权的有向图,表示城市间的道路和距离,例如:

  • 城市A到城市B的距离是3
  • 城市A到城市C的距离是9
  • 城市B到城市C的距离是2
    Dijkstra算法可以用来找到从城市A出发到其他所有城市的最短路径。在这个例子中,从城市A到城市C的最短路径是A→B→C,总距离为5。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV视频I/O(5)视频采集类VideoCapture之从视频流中获取下一帧的函数grab()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 从视频文件或捕获设备中抓取下一帧。 grab() 函数是 OpenCV 中 VideoCapture 类的一个成员函数&#xff0c;用于从视频流中获取下一帧而不立即检…

Android Studio 真机USB调试运行频繁掉线问题

一、遇到问题 Android Studio使用手机运行项目时&#xff0c;总是频繁掉线&#xff0c;连接很不稳定&#xff0c;动不动就消失&#xff0c;基本上无法使用 二、问题出现原因 1、硬件问题&#xff1a;数据线 换条数据线试试&#xff0c;如果可以&#xff0c;那就是数据线的…

element plus block报错

解决&#xff1a; ::v-deep input[aria-hidden"true"] {display: none !important }

9.3 Linux_I/O_文件I/O相关函数

打开与关闭 1、打开文件 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);返回值&#xff1a;成功返回文件描述符&#xff0c;失败返回EOF pathname&#xff1a;文件路径 flags&#xff1a;标志&#xff0c;其中O_RDO…

《面向对象是怎样工作的》笔记

6、1、在面向对象的世界中&#xff0c;我们需要事先为所有的行动准备好方法并通过消息传递来调用方法&#xff0c;这样事物才会开始运作。 2、实际上&#xff0c;类、继承和多态应该被明确定义为能提高软件的可维护性和可重用行的结构。类将变量和子程序汇总在一起&#xff0c…

Vue 技术入门 day1 模版语法、数据绑定、事件处理、计算属性与监视、class和style绑定、条件渲染v-if/v-show、列表渲染v-for

目录 1.Vue 核心 1.1. Vue 简介 1.1.1 介绍与描述 1.1.2 Vue 的特点 1.2 模板语法 1.2.1 模板的分类 1.2.2 插值语法 1.2.3 指令语法 1.2.4 实例 1.3 数据绑定 1.3.1 单向数据绑定 1.3.2 双向数据绑定 1.3.3 MVVM 模型 1.3.4 data与el的2种写法 1.3.5 实例 1.3.…

信息安全工程师(25)网络安全体系框架主要组成和建设内容

一、主要组成 信息安全战略&#xff1a;确立组织的信息安全目标和方向&#xff0c;指导整个网络安全体系的建设和运营。信息安全政策和标准&#xff1a;制定和执行一系列信息安全政策、标准和规范&#xff0c;确保网络安全活动有法可依、有章可循。信息安全管理&#xff1a;包括…

网站建设中常见的网站后台开发语言有哪几种,各自优缺点都是什么?

市场上常见的网站后台开发语言有PHP、Python、JavaScript、Ruby、Java和.NET等。这些语言各有其独特的优缺点&#xff0c;适用于不同的开发场景和需求。以下是对这些语言的具体介绍&#xff1a; PHP 优点&#xff1a;PHP是一种广泛用于Web开发的动态脚本语言&#xff0c;特别适…

《论文阅读》 用于产生移情反应的迭代联想记忆模型 ACL2024

《论文阅读》 用于产生移情反应的迭代联想记忆模型 ACL2024 前言简介任务定义模型架构Encoding Dialogue InformationCapturing Associated InformationPredicting Emotion and Generating Response损失函数问题前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦…

成都睿明智科技有限公司赋能商家高效变现

在这个日新月异的数字时代&#xff0c;抖音电商正以不可阻挡之势崛起&#xff0c;成为众多品牌与商家竞相角逐的新战场。在这片充满机遇与挑战的蓝海中&#xff0c;成都睿明智科技有限公司如同一颗璀璨新星&#xff0c;凭借其专业的服务、创新的策略和敏锐的市场洞察&#xff0…

NLP 文本分类任务核心梳理

解决思路 分解为多个独立二分类任务将多标签分类转化为多分类问题更换 loss 直接由模型进行多标签分类 数据稀疏问题 标注更多数据&#xff0c;核心解决方案&#xff1a; 自己构造训练样本 数据增强&#xff0c;如使用 chatGPT 来构造数据更换模型 减少数据需求增加规则弥补…

[element-ui]记录对el-table表头样式的一些处理

1、表头换行 & 列表项换行 可用element-table组件自带的方法实现列标题换行的效果 2、小圆点样式

第五部分:5---三张信号表,信号表的系统调用

目录 信号的递达、未决、阻塞&#xff1a; 进程维护的三张信号表&#xff1a; 普通信号与实时信号的记录&#xff1a; 信号结构的系统调用&#xff1a; bolck表的系统调用&#xff1a; 实例&#xff1a;设置屏蔽信号集中的所有信号都频闭 pending表读取&#xff1a; 信号…

计算机网络——TCP/IP网络模型

1. TCP/IP网络模型有哪几层 对于同一台设备上的进程间通信&#xff0c;有很多种方式&#xff0c;比如管道、消息队列、共享内存、信号等。而对于不同设备上的进程间通信&#xff0c;就需要网络通信&#xff0c;而设备是多样性的&#xff0c;所以要兼容多种多样的设备&#xff…

STM32快速复习(十二)FLASH闪存的读写

文章目录 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f;二、使用步骤1.标准库函数2.示例函数 总结 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f; 1、FLASH简介 &#xff08;1&#xff09;STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&…

Java每日面试题(JVM)(day15)

目录 Java对象内存布局markWord 数据结构JDK1.8 JVM 内存结构JDK1.8堆内存结构GC垃圾回收如何发现垃圾如何回收垃圾 JVM调优参数 Java对象内存布局 markWord 数据结构 JDK1.8 JVM 内存结构 程序计数器: 线程私有&#xff0c;记录代码执行的位置. Java虚拟机栈: 线程私有&#…

HarmonyOS鸿蒙系统开发应用程序,免费开源DevEco Studio开发工具

DevEco Studio 是华为为 HarmonyOS 和 OpenHarmony 开发者提供的官方集成开发环境&#xff08;IDE&#xff09;&#xff0c;它基于 IntelliJ IDEA Community 版本打造&#xff0c;提供了代码编辑、编译、调试、发布等一体化服务。 一、DevEco Studio支持系统 DevEco Studio支持…

Centos怎么执行脚本

方法一&#xff1a;切换到shell脚本所在的目录&#xff08;此时&#xff0c;称为工作目录&#xff09;执行shell脚本 cd /data/shell ./hello.sh 方法二&#xff1a;以绝对路径的方式去执行bash shell脚本 /data/shell/hello.sh 方法三&#xff1a;直接使用bash 或sh 来执行…

中国算力大会启幕,联想发布异构智算产业创新成果

9月27日&#xff0c;2024中国算力大会在河南郑州拉开帷幕。作为全球领先的算力基础设施和服务提供商&#xff0c;联想集团参会参展并携手异构智算产业联盟承办2024异构智算产业生态联盟技术论坛。 据「TMT星球」了解&#xff0c;论坛发布了新一代AI服务器、AI应用部署解决方案…

飞睿智能实时雷达活体探测传感器模块,智能家居静止检测实时感知人员有无

随着科技的飞速发展&#xff0c;我们的生活正在经历着未有的创新。在这个创新的浪潮中&#xff0c;实时雷达活体探测传感器模块的技术正逐渐崭露头角&#xff0c;以其独特的优势为我们的生活带来安全与便捷。今天&#xff0c;我们就来详细探讨一下这项技术&#xff0c;看看它是…