DAY63||拓扑排序精讲 |dijkstra(朴素版)精讲

news2024/12/23 4:21:27

拓扑排序精讲

117. 软件构建

题目描述

某个大型软件项目的构建系统拥有 N 个文件,文件编号从 0 到 N - 1,在这些文件中,某些文件依赖于其他文件的内容,这意味着如果文件 A 依赖于文件 B,则必须在处理文件 A 之前处理文件 B (0 <= A, B <= N - 1)。请编写一个算法,用于确定文件处理的顺序。

输入描述

第一行输入两个正整数 N, M。表示 N 个文件之间拥有 M 条依赖关系。

后续 M 行,每行两个正整数 S 和 T,表示 T 文件依赖于 S 文件。

输出描述

输出共一行,如果能处理成功,则输出文件顺序,用空格隔开。 

如果不能成功处理(相互依赖),则输出 -1。

输入示例

5 4
0 1
0 2
1 3
2 4

输出示例

0 1 2 3 4

提示信息

文件依赖关系如下:

所以,文件处理的顺序除了示例中的顺序,还存在

0 2 4 1 3

0 2 1 3 4

等等合法的顺序。

数据范围:

0 <= N <= 10 ^ 5

1 <= M <= 10 ^ 9

每行末尾无空格。

概括来说,给出一个 有向图,把这个有向图转成线性的排序 就叫拓扑排序

当然拓扑排序也要检测这个有向图 是否有环,即存在循环依赖的情况,因为这种情况是不能做线性排序的。

所以拓扑排序也是图论中判断有向无环图的常用方法

其实只要能在把 有向无环图 进行线性排序 的算法 都可以叫做 拓扑排序。

实现拓扑排序的算法有两种:卡恩算法(BFS)和DFS。

 出发节点:当我们做拓扑排序的时候,应该优先找 入度为 0 的节点,只有入度为0,它才是出发节点。 

 拓扑排序的过程,其实就两步:

  1. 找到入度为0 的节点,加入结果集
  2. 将该节点从图中移除

循环以上两步,直到 所有节点都在图中被移除了。

模拟过程

用本题的示例来模拟这一过程:

1、找到入度为0 的节点,加入结果集

2、将该节点从图中移除


1、找到入度为0 的节点,加入结果集

这里大家会发现,节点1 和 节点2 入度都为0, 选哪个呢?

选哪个都行,所以这也是为什么拓扑排序的结果是不唯一的。

2、将该节点从图中移除


1、找到入度为0 的节点,加入结果集

节点2 和 节点3 入度都为0,选哪个都行,这里选节点2

2、将该节点从图中移除


后面的过程一样的,节点3 和 节点4,入度都为0,选哪个都行。

最后结果集为: 0 1 2 3 4 。当然结果不唯一的

有环的情况

只有一个结果,因为接下来找不到一个入度为0的节点了

模拟运行结果

假设输入如下:

4 6
0 1
1 2
2 3
3 4
4 5
  • 首先读取 m=4n=6,初始化 inDegreeumap

  • 读取依赖关系:

    • 0 -> 1inDegree[1]++umap[0].push_back(1)
    • 1 -> 2inDegree[2]++umap[1].push_back(2)
    • 2 -> 3inDegree[3]++umap[2].push_back(3)
    • 3 -> 4inDegree[4]++umap[3].push_back(4)
    • 4 -> 5inDegree[5]++umap[4].push_back(5)
  • 初始化队列,入度为0的节点是 0,将其加入队列。

  • 拓扑排序:

    • cur = 0result.push_back(0),处理 0 指向的文件 1inDegree[1]--inDegree[1] == 0,将 1 加入队列。
    • cur = 1result.push_back(1),处理 1 指向的文件 2inDegree[2]--inDegree[2] == 0,将 2 加入队列。
    • cur = 2result.push_back(2),处理 2 指向的文件 3inDegree[3]--inDegree[3] == 0,将 3 加入队列。
    • cur = 3result.push_back(3),处理 3 指向的文件 4inDegree[4]--inDegree[4] == 0,将 4 加入队列。
    • cur = 4result.push_back(4),处理 4 指向的文件 5inDegree[5]--inDegree[5] == 0,将 5 加入队列。
    • cur = 5result.push_back(5),处理 5 指向的文件,没有文件。
  • 最终结果集 result[0, 1, 2, 3, 4, 5],大小为6,等于文件数 n

  • 输出结果:

    0 1 2 3 4 5

代码

思想简单,但是代码却不简单。

1.初始化的时候,就把每个节点的入度 和 每个节点的依赖关系做统计。

2.找入度为0 的节点,需要用一个队列放存放。

3.开始从队列里遍历入度为0 的节点,将其放入结果集。

4.将 该节点作为出发点所连接的节点的 入度 减一(类似把节点移除出图,但不是真移除)

#include<iostream>
#include<vector>
#include<queue>
#include<unordered_map>
using namespace std;
int main()
{
    int m,n,s,t;//依赖关系数,文件数0到n-1,具体文件的依赖关系st
    cin>>n>>m;
    vector<int>inDegree(n,0);//每个节点的入度关系
    vector<int>result;//结果
    unordered_map<int,vector<int>>umap;//记录文件依赖关系
    
    while(m--)
    {
        cin>>s>>t;
        inDegree[t]++;//因为t依赖s,所以t的入度关系自增
        umap[s].push_back(t);//记录s指向的文件
    }
    
    queue<int>que;//存放入度为0的节点
    for(int i=0;i<n;i++)
    {
        if(inDegree[i]==0)que.push(i);
    }
    
    while(que.size())
    {
        int cur=que.front();
        que.pop();
        result.push_back(cur);//结果集记录入度为0的节点,先入先出
        
        vector<int>files=umap[cur];//获取当前文件及其指向文件
        
        if(files.size())
        {
            for(int i=0;i<files.size();i++)//遍历所有指向的文件。
            {
                inDegree[files[i]]--;// cur的指向的文件入度-1
                if(inDegree[files[i]]==0)que.push(files[i]);//只要入度为0,就饿可以加入队列中
            }
        }
    }
    if(result.size()==n)//如果结果集的大小等于文件数 n,说明所有文件都能正确排序。
    {
        for(int i=0;i<n-1;i++)
        cout<<result[i]<<" ";
        cout<<result[n-1];
    }
    else cout<<-1<<endl;
}

dijkstra(朴素版)精讲

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

题目描述

小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。

小明的起点是第一个车站,终点是最后一个车站。然而,途中的各个车站之间的道路状况、交通拥堵程度以及可能的自然因素(如天气变化)等不同,这些因素都会影响每条路径的通行时间。

小明希望能选择一条花费时间最少的路线,以确保他能够尽快到达目的地。

输入描述

第一行包含两个正整数,第一个正整数 N 表示一共有 N 个公共汽车站,第二个正整数 M 表示有 M 条公路。 

接下来为 M 行,每行包括三个整数,S、E 和 V,代表了从 S 车站可以单向直达 E 车站,并且需要花费 V 单位的时间。

输出描述

输出一个整数,代表小明从起点到终点所花费的最小时间。

输入示例

7 9
1 2 1
1 3 4
2 3 2
2 4 5
3 4 2
4 5 3
2 6 4
5 7 4
6 7 9

输出示例

12

提示信息

能够到达的情况:

如下图所示,起始车站为 1 号车站,终点车站为 7 号车站,绿色路线为最短的路线,路线总长度为 12,则输出 12。

不能到达的情况:

如下图所示,当从起始车站不能到达终点车站时,则输出 -1。

数据范围:

1 <= N <= 500;
1 <= M <= 5000;

最短路是图论中的经典问题即:给出一个有向图,一个起点,一个终点,问起点到终点的最短路径。 

dijkstra算法:在有权图(权值非负数)中求从起点到其他节点的最短路径算法。

需要注意两点:

  • dijkstra 算法可以同时求 起点到所有节点的最短路径
  • 权值不能为负数

dijkstra 算法 同样是贪心的思路,不断寻找距离 源点最近的没有访问过的节点。

这里我也给出 dijkstra三部曲

  1. 第一步,选源点到哪个节点近且该节点未被访问过
  2. 第二步,该最近节点被标记访问过
  3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)(注意这里的mindist记录的是离源点的距离!!!)

 和prim算法很像。

模拟过程

1-2-3-4-6-5-7

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

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

以此类推,到第7节点时

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


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

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

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

路径如图:

代码例子
4 4
1 2 1
1 3 4
2 3 1
3 4 1
  • 首先读取 n=4m=4,初始化邻接矩阵 grid

  • 读取边并填充邻接矩阵:

    • 边 (1, 2, 1)grid[1][2] = 1
    • 边 (1, 3, 4)grid[1][3] = 4
    • 边 (2, 3, 1)grid[2][3] = 1
    • 边 (3, 4, 1)grid[3][4] = 1
  • 初始化 minDistvisited

  • 运行 Dijkstra 算法:

    • 第一次迭代:选择节点1,更新 minDist 为 [0, 1, 4, INT_MAX]
    • 第二次迭代:选择节点2,更新 minDist 为 [0, 1, 2, INT_MAX]
    • 第三次迭代:选择节点3,更新 minDist 为 [0, 1, 2, 3]
    • 第四次迭代:选择节点4,minDist 保持不变。
  • 最终输出:

    3

代码 

#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
    int n,m,p1,p2,val;//公共汽车站数量,公路数量,某站到某站及其所花时间
    cin>>n>>m;
    //声明一个大小为 (n + 1) x (n + 1) 的二维向量 grid,用于存储图的邻接矩阵。初始值为 INT_MAX,表示不存在的边或非常大的权值。
    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;
    //存储从源点到每个节点的最短距离
    vector<int>minDist(n+1,INT_MAX);
    
    //记录顶点是否被访问过
    vector<bool>visited(n+1,false);
    
    minDist[start]=0;//起始点到自身的距离为0
    
    for(int i=1;i<=n;i++)//遍历所有节点
    {
        int minval=INT_MAX;
        int cur=1;
        
        //第一步,选距离源点最近且未被访问过的节点
        for(int j=1;j<=n;j++)
        {
            if(!visited[j]&&minDist[j]<minval)
            {
                minval=minDist[j];
                cur=j;
            }
        }
        //第二步,标记当前节点为已被访问
        visited[cur]=true;
        
        //第三步,更新非访问节点到源点的距离(更新mindist数组)
        for(int k=1;k<=n;k++)
        {
            if(!visited[k]&&grid[cur][k]!=INT_MAX&&minDist[cur]+grid[cur][k]<minDist[k])
            {
                minDist[k]=minDist[cur]+grid[cur][k];
            }
        }
    }
    if(minDist[end]==INT_MAX)cout<<-1<<endl;//表示不能到达终点
    else
    cout<<minDist[end]<<endl;//最后一个节点有更新的值,就是最短路径的结果
}

和prim算法的区别

prim是求 非访问节点到最小生成树的最小距离,而 dijkstra是求 非访问节点到源点的最小距离

prim 更新 minDist数组的写法:

for (int j = 1; j <= v; j++) {
    if (!isInTree[j] && grid[cur][j] < minDist[j]) {
        minDist[j] = grid[cur][j];
    }
}

因为 minDist表示 节点到最小生成树的最小距离,所以 新节点cur的加入,只需要 使用 grid[cur][j] ,grid[cur][j] 就表示 cur 加入生成树后,生成树到 节点j 的距离

dijkstra 更新 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];
    }
}

因为 minDist表示 节点到源点的最小距离,所以 新节点 cur 的加入,需要使用 源点到cur的距离 (minDist[cur]) + cur 到 节点 v 的距离 (grid[cur][v]),才是 源点到节点v的距离。

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

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

相关文章

爬虫补环境案例---问财网(rpc,jsdom,代理,selenium)

目录 一.环境检测 1. 什么是环境检测 2.案例讲解 二 .吐环境脚本 1. 简介 2. 基础使用方法 3.数据返回 4. 完整代理使用 5. 代理封装 6. 封装所有使用方法 jsdom补环境 1. 环境安装 2. 基本使用 3. 添加参数形式 Selenium补环境 1. 简介 2.实战案例 1. 逆向目…

DICOM图像解析:深入解析DICOM格式文件的高效读取与处理(续)

目录 一、DICOM图像高效解析 1、处理压缩的像素数据 常见压缩算法及其处理方法 解压缩示例 2、多帧图像的处理 多帧图像解析流程 三维图像的体绘制 3、序列和嵌套数据元素 序列数据的解析 二、错误处理与数据验证 常见错误类型 错误处理策略 三、使用现有的DICOM库…

「QT」高阶篇 之 d-指针 的用法

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定制…

如何绑定洛谷账号

首先注册洛谷 然后登陆 点击键盘F12 点击加号 点击应用程序 在name中找到__client_id和_uid 再复制相应的value到下图右侧 然后点击confirm即可 愿我们都能成为我们想要去成为的人&#xff01; 花会沿路盛开&#xff0c;我们以后的路也会&#xff01; 追风赶月莫停留&…

5G CPE:为什么活动会场与商铺的网络成为最新选择

在快节奏的现代社会中&#xff0c;无论是举办一场盛大的活动还是经营一家繁忙的商铺&#xff0c;稳定的网络连接都是不可或缺的基石。然而&#xff0c;面对复杂的布线难题或高昂的商业宽带费用&#xff0c;许多场所往往陷入两难境地。幸运的是&#xff0c;5G CPE&#xff08;Cu…

【ACM独立出版|高校主办】第四届信号处理与通信技术国际学术会议(SPCT 2024)

第四届信号处理与通信技术国际学术会议&#xff08;SPCT 2024&#xff09; 2024 4th International Conference on Signal Processing and Communication Technology 2024年12月27-29日 中国深圳 www.icspct.com 会议亮点&#xff1a; 1、ACM独立出版&#xff0c;EI稳…

CPU的性能指标总结(学习笔记)

CPU 性能指标 我们先来回顾下&#xff0c;描述 CPU 的性能指标都有哪些。 首先&#xff0c;最容易想到的应该是 CPU 使用率&#xff0c;这也是实际环境中最常见的一个性能指标。 用户 CPU 使用率&#xff0c;包括用户态 CPU 使用率&#xff08;user&#xff09;和低优先级用…

python 同时控制多部手机

在这个智能时代,我们的手机早已成为生活和工作中不可或缺的工具。无论是管理多个社交媒体账号,还是处理多台设备上的事务,如何更高效地控制多个手机成为了每个人的痛点。 今天带来的这个的软件为你提供了一键控制多部手机的强大功能。无论是办公、娱乐,还是社交,你都能通过…

实用教程:如何无损修改MP4视频时长

如何在UltraEdit中搜索MP4文件中的“mvhd”关键字 引言 在视频编辑和分析领域&#xff0c;有时我们需要深入到视频文件的底层结构中去。UltraEdit&#xff08;UE&#xff09;和UEStudio作为强大的文本编辑器&#xff0c;允许我们以十六进制模式打开和搜索MP4文件。本文将指导…

java项目-jenkins任务的创建和执行

参考内容: jenkins的安装部署以及全局配置 1.编译任务的general 2.源码管理 3.构建里编译打包然后copy复制jar包到运行服务器的路径 clean install -DskipTests -Pdev 中的-Pdev这个参数用于激活 Maven 项目中的特定构建配置&#xff08;Profile&#xff09; 在 pom.xml 文件…

【扩散——BFS】

题目 代码 #include <bits/stdc.h> using namespace std; const int t 2020, off 2020; #define x first #define y second typedef pair<int, int> PII; int dx[] {0, 0, 1, -1}, dy[] {-1, 1, 0, 0}; int dist[6080][6080]; // 0映射到2020&#xff0c;2020…

C++编程:利用环形缓冲区优化 TCP 发送流程,避免 Short Write 问题

文章目录 1. 什么是 Short Write 问题&#xff1f;2. 如何解决 Short Write 问题&#xff1f;2.1 方法 1&#xff1a;将 Socket 设置为阻塞模式2.2 方法 2&#xff1a;用户态维护发送缓冲区 3. 用户态维护发送缓冲区实现3.1 核心要点3.2 代码实现3.3 测试程序 参考文档 1. 什么…

数据网格能替代数据仓库吗?

一、数据网格是什么&#xff1f; 数据网格&#xff1a;是一种新兴的数据管理架构和理念&#xff0c;主要用于解决大规模、复杂数据环境下的数据管理和利用问题。 核心概念&#xff1a; 1、数据即产品&#xff1a;将数据看作一种产品&#xff0c;每个数据域都要对其生产的数据负…

力扣经典面试26题删除有序数组中的重复项1

给你一个非严格递增排列的数组nums&#xff0c;请你原地删除重复出现的元素&#xff0c; 使每个元素 只出现一次&#xff0c;返回删除后数组的新长度。元素的相对顺序 应该保持 一致。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k&#xff0c; 你需要做以…

LLM: AI Mathematical Olympiad (上)

文章目录 一、项目简介二、first place 攻略三、必备知识1、COT思维链技术2、ToRA 四、first place 训练功略五、数据集构建1、COT数据集2、TIR数据集 六、数据集详细技术报告总结 本文较长分成两个部分分析 | ू•ૅω•́)ᵎᵎᵎ 第一部分&#xff1a;预备知识介绍和数据准备…

GA/T1400视图库平台EasyCVR视频融合平台HLS视频协议是什么?

在数字化时代&#xff0c;视频监控系统已成为保障安全、提升效率的关键技术。EasyCVR视频融合云平台&#xff0c;作为TSINGSEE青犀视频在“云边端”架构体系中的重要一环&#xff0c;专为大中型项目设计&#xff0c;提供了一个跨区域、网络化的视频监控综合管理系统平台。它不仅…

给阿里云OSS绑定域名并启用SSL

为什么要这么做&#xff1f; 问题描述&#xff1a; 当用户通过 OSS 域名访问文件时&#xff0c;OSS 会在响应头中增加 Content-Disposition: attachment 和 x-oss-force-download: true&#xff0c;导致文件被强制下载而不是预览。这个问题特别影响在 2022/10/09 之后新开通 OS…

`node-gyp` 无法找到版本为 `10.0.19041.0` 的 Windows SDK

从你提供的错误信息来看&#xff0c;问题出在 node-gyp 无法找到版本为 10.0.19041.0 的 Windows SDK。我们可以尝试以下几种方法来解决这个问题&#xff1a; 完整示例 方法 1&#xff1a;安装指定版本的 Windows SDK 下载并安装 Windows SDK&#xff1a; 访问 Windows SDK 下…

【Hive】【HiveQL】【大数据技术基础】 实验四 HBase shell命令实验

实验四&#xff1a;熟悉常用的HBase操作 实验概览 在本次实验中&#xff0c;我们将深入探索HBase在Hadoop生态系统中的角色&#xff0c;并熟练掌握常用的HBase Shell命令和Java API操作。通过这些实践&#xff0c;我们能够更好地理解HBase的工作原理以及如何在实际项目中应用。…

3D意识(3D Awareness)浅析

一、简介 3D意识&#xff08;3D Awareness&#xff09;主要是指视觉基础模型&#xff08;visual foundation models&#xff09;对于3D结构的意识或感知能力&#xff0c;即这些模型在处理2D图像时是否能够理解和表示出图像中物体或场景的3D结构&#xff0c;其具体体现在编码场景…