图——图的应用02最短路径(Dijkstra算法与Floyd算法详解),拓扑排序及关键路径

news2024/12/24 2:15:51

前面介绍了图的应用——01最小生成树章节,大家可以通过下面的链接学习:

图——图的应用01最小生成树(Prim算法与Kruskal算法详解)

今天就讲一下图的其他应用——最短路径,拓扑排序及关键路径。

目录

一,最短路径

1,Dijkstra(迪杰斯特拉)算法

Dijkstra算法思想

c语言中Dijkstra算法的完整代码: 

2, Floyd(弗洛伊德)算法

 Floyd算法思想:

c语言中Floyd算法的完整代码:

二,拓扑排序

三,关键路径


一,最短路径

两种常见的最短路径问题:

一、 单源最短路径Dijkstra(迪杰斯特拉)算法

二、所有顶点间的最短路径Floyd(弗洛伊德)算法

1,Dijkstra(迪杰斯特拉)算法

Dijkstra算法思想

1.初始化:先找出从源点v0到各终点vk的直达路径(v0,vk),即通过一条弧到达的路径。

2.选择:从这些路径中找出一条长度最短的路径(v0,u)。

3.更新:然后对其余各条路径进行适当调整,即:

v0到其余各点的最短路径--按路径长度递增次序求解 

1、把V分成两组

(1) S:已求出最短路径的顶点的集合。

(2) T=V -S:尚未确定最短路径的顶点集合。

2、将T中顶点按最短路径递增的次序加入到S中,

保证

(1)从源点v0到S中各顶点的最短路径长度都不大于从v0到T中任何顶点的最短路径长度。

(2)每个顶点对应一个距离值

S中顶点:从v0到此顶点的最短路径长度。

T中顶点:从v到此顶点的只包括S中顶点作中间顶点的最短路径长度。

下面是一个实例——

c语言中Dijkstra算法的完整代码: 

#include <stdio.h>
#include <limits.h>

#define V 9

// 函数minDistance用于找到距离源节点最近的节点
int minDistance(int dist[], int sptSet[]) {
    int min = INT_MAX, min_index;
    // 遍历所有节点,找到距离源节点最近的节点
    for (int v = 0; v < V; v++)
        if (sptSet[v] == 0 && dist[v] <= min)
            min = dist[v], min_index = v;
    return min_index;
}

// 函数printSolution用于打印最短路径
void printSolution(int dist[]) {
    printf("Vertex \t\t Distance from Source");
    // 遍历所有节点,打印最短路径
    for (int i = 0; i < V; i++)
        printf("%d \t\t %d", i, dist[i]);
}

// 函数dijkstra用于计算最短路径
void dijkstra(int graph[V][V], int src) {
    int dist[V];
    int sptSet[V];

    // 初始化距离数组和最短路径集合
    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX, sptSet[i] = 0;

    dist[src] = 0;

    // 遍历所有节点,计算最短路径
    for (int count = 0; count < V - 1; count++) {
        int u = minDistance(dist, sptSet);
        sptSet[u] = 1;

        // 更新距离数组
        for (int v = 0; v < V; v++)
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v])
                dist[v] = dist[u] + graph[u][v];
    }

    printSolution(dist);
}

int main() {
    int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                       {4, 0, 8, 0, 0, 0, 0, 11, 0},
                       {0, 8, 0, 7, 0, 4, 0, 0, 2},
                       {0, 0, 7, 0, 9, 14, 0, 0, 0},
                       {0, 0, 0, 9, 0, 10, 0, 0, 0},
                       {0, 0, 4, 14, 10, 0, 2, 0, 0},
                       {0, 0, 0, 0, 0, 2, 0, 1, 6},
                       {8, 11, 0, 0, 0, 0, 1, 0, 7},
                       {0, 0, 2, 0, 0, 0, 6, 7, 0}};

    dijkstra(graph, 0);

    return 0;
}

 结果如下:

 Vertex      Distance from Source
0      0
1      4
2      12
3      19
4      21
5      11
6      9
7      8
8      14

2, Floyd(弗洛伊德)算法

求所有顶点间的最短路径有两种方法:

方法一每次以一个顶点为源点,重复执行Dijkstra算法n次

方法二弗洛伊德(Floyd)算法。

 Floyd算法思想:

1逐个顶点试探;

2𝑣𝑖v_i𝑣𝑗v_j的所有可能存在的路径中

3选出一条长度最短的路径

c语言中Floyd算法的完整代码:

与之前同样使用了“limits”库, "INF"表示两个顶点之间没有路径。使用INT_MAX来表示无穷大,当两个顶点之间没有直接路径时,它们的距离就是无穷大。

#include <stdio.h>
#include <limits.h>

#define V 4

// 打印最短路径矩阵
void printSolution(int dist[][V]);

// Floyd-Warshall算法
void floydWarshall(int graph[][V]) {
    int dist[V][V], i, j, k;

    // 初始化距离矩阵
    for (i = 0; i < V; i++)
        for (j = 0; j < V; j++)
            dist[i][j] = graph[i][j];

    // 三重循环,计算最短路径
    for (k = 0; k < V; k++) {
        for (i = 0; i < V; i++) {
            for (j = 0; j < V; j++) {
                if (dist[i][k] + dist[k][j] < dist[i][j])
                    dist[i][j] = dist[i][k] + dist[k][j];
            }
        }
    }

    // 打印最短路径矩阵
    printSolution(dist);
}

// 打印最短路径矩阵
void printSolution(int dist[][V]) {
    printf("以下是最短路径矩阵:");
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (dist[i][j] == INT_MAX)
                printf("%7s", "INF");
            else
                printf("%7d", dist[i][j]);
        }
        printf(" \n");
    }
}

int main() {
    int graph[V][V] = {{0, 5, INT_MAX, 10},
                       {INT_MAX, 0, 3, INT_MAX},
                       {INT_MAX, INT_MAX, 0, 1},
                       {INT_MAX, INT_MAX, INT_MAX, 0}};

    // 调用Floyd-Warshall算法
    floydWarshall(graph);
    return 0;
}

输出结果: 

 以下是最短路径矩阵:
   0     5     8     9
 INF     0     3     4
 INF  INF     0     1
 INF  INF  INF     0

二,拓扑排序

首先我们需要知道拓扑排序是针对有向无环图(DAG)的,在实例中,我们经常用有向图来描述一个工程或系统的进行过程。一个工程可以分为若干个子工程,只要完成了这些子工程(活动),就可以导致整个工程的完成。

表示活动有两种方式:

AOV网(Activity  On Vertices)—用顶点表示活动的网络,对应拓扑排序算法

AOE网(Activity  On Edges)—用边表示活动的网络,对应关键路径算法

比如教学计划的制定

哪些课程是必须先修的,哪些课程是可以并行学习的

813a3be2128d421087bfe1658d8d3572.png

38b2742be8b1426ca253d0ca2274dcdc.png

AOV网特点

1.若从顶点Vi到顶点Vj有路径(有向边),则Vi 是Vj 的(直接)前驱; Vj 是Vi 的(直接)后继。

2.AOV网不能存在回路。

3.拓扑排序,所有顶点排成一个线性序列。

无环有向图的判断方法: 若网中顶点都在拓扑有序序列中,则AOV-网。不存在环。

拓扑排序算法的思想:重复选择没有直接前驱的顶点。

具体步骤如下: 

1.输入AOV网络。令 n 为顶点个数。

2.在AOV网络中选一个没有直接前驱的顶点, 并输出之;

3.从图中删去该顶点, 同时删去所有它发出的有向边;

重复以上 2、3 步, 直到:

         全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;

         或:

        图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。

我们仍以教学计划的制定为例分析此过程:

•对学生选课工程图进行拓扑排序,得到的拓扑有序序列为

      C1 , C2 , C3 , C4 , C5 , C6 , C8 , C9 , C7

或  C1 , C8 , C9 , C2 , C5 , C3 , C4 , C7 , C6 

31b26f9a550947cd8d581d01f5a8da5e.png

三,关键路径

        用途:估算工程项目完成时间

        AOE网络:定义结点为事件,有向边的指向表示事件的执行次序。单位是时间(时刻)。有向边定义为活动,它的权值定义为活动进行所需要的时间。

8045c414e31348acb08fb1e8ac408c2b.png

5c892b536ebb4c79a1ef8d598ab61265.png

•   术语:

    源点:表示整个工程的开始点,也称起点(入度为0)。

    收点:表示整个工程的结束点,也称汇点(出度为0)。

9fe1fbecdbd8420cbab322544928daee.png

求解关键路径,我们还需要知道以下概念: 

f3f8def6bf304836b8d878302ebc4b2a.png

 那么该如何求这些值?6ffb4656b9894b47a12741dcb808540c.png

     Ve(j) 及 Vl(j))的求法:

7a9e67218b7e42c1b8517ed568c5294f.png

 我们可以看出,关键路径就是通过加总最长路径上所有活动的持续时间来确定的项目最短完成时间。

下面是另一个例子

991655bc1e2941a39241dcb4ba6e19bf.png

995703f57952446a9c943c09071ca501.png

4dc397c367da41c8a924934b19f1497b.png

因此我们就求出了此活动的关键路径

242c9bfb467749ff90746707f33a02c7.png


图的应用章节就到此结束啦,不知道大家有没有掌握呢?

如果文章对你有用的话请点个赞支持一下吧!

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

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

相关文章

解决Qt6 OpenCV项目编译出现错误undefined reference to symbol ‘cv::cvtColor,无法解析的符号

在一次Qt6 OpenCV项目编译的过程中&#xff0c;出现错误undefined reference to symbol cv::cvtColor&#xff0c;无法解析的符号&#xff0c;问题是查看INCLUDEPATH和LIBS&#xff0c;都已经添加正确。 而且这个函数也可以在头文件中索引到。到底是什么问题呢&#xff1f; 清…

公司政务办理流程分享(北京)

社保增减员&#xff1a; 参保登记——增减员业务这么办_北京市人力资源和社会保障局_社会保险 https://rsj.beijing.gov.cn/yltc/202310/t20231025_3287007.html 公积金增减员&#xff1a; https://dwwsyw.gjj.beijing.gov.cn/

【从零开始实现stm32无刷电机FOC】【实践】【5/6 stm32 adc外设的高级用法】

目录 采样时刻触发采样同步采样 点击查看本文开源的完整FOC工程 本节介绍的adc外设高级用法用于电机电流控制。 从前面几节可知&#xff0c;电机力矩来自于转子的q轴受磁力&#xff0c;而磁场强度与电流成正比&#xff0c;也就是说电机力矩与q轴电流成正相关&#xff0c;控制了…

which 命令在Linux中是一个快速查找可执行文件位置的工具

文章目录 0、概念1、which --help2、which命令解释 0、概念 which命令用于查找命令的可执行文件的路径which 命令在 Linux 中用于查找可执行命令的完整路径。当你在 shell 中输入一个命令时&#xff0c;shell 会在环境变量 $PATH 定义的目录列表中查找这个命令。which 命令可以…

数据结构——单链表详解(超详细)(2)

前言&#xff1a; 上一篇文章小编简单的介绍了单链表的概念和一些函数的实现&#xff0c;不过为了保证文章的简洁&#xff0c;小编把它分成了两篇来写&#xff0c;这一篇小编紧接上一篇文章继续写单链表函数功能的实现&#xff1a; 目录&#xff1a; 1.单链表剩余函数的编写 1.…

Spring Security Oauth2源码分析

Spring Security Oauth2源码分析 前言一&#xff1a;客户端OAuth2授权请求的入口1、DefaultOAuth2AuthorizationRequestResolver类OAuth2AuthorizationRequest类authorizationRequestUri 的构建机制redirectUri 3、OAuth2AuthorizationRequestRedirectFilter类 二&#xff1a;O…

hiphop音乐风格分类有几种 怎么使用FL Studio制作Hip Hop音乐 hiphop音乐制作教程

Hip Hop音乐是一类新潮的音乐风格&#xff0c;融合了许多不同的文化元素和音乐表达方式。嘻哈&#xff08;hip hop&#xff09;诞生于美国贫民区街头的一种文化形式&#xff0c;一般的说法认为它诞生于美国纽约布朗克斯。嘻哈首先在纽约市北部布朗克斯市区的非裔及拉丁裔青年之…

kali进行host碰撞实验

目录 在kali上安装docker&#xff0c;完成环境搭建&#xff0c;进行host碰撞实验 更新软件包列表 下载阿里云的镜像源 添加 GPG 密钥并添加更新源 安装 Docker 安装成功检验 开启docker 检查docker状态 拉取镜像 在kali访问ip&#xff08;加端口&#xff09; 下载压缩…

京东超级18活动入口!京东超级18活动怎么玩?

京东推出新活动&#xff0c;低价的持续性项目“京东超级18”。 活动入口&#xff1a; 京东超级18&#xff0c;领60元大额补贴&#xff01; 口令直达&#xff1a;14:/京东超级18&#xffe5;NF5fuBPWIIaHRiMr&#xffe5;&#xff0c;↗鯨○Dσσδng。 手机京东搜索&#xf…

Claude 3.5 Sonnet模型发布,对比ChatGPT4o孰强孰弱

Anthropic 这家生而为打击 OpenAI 安全问题的公司&#xff0c;正式发布了Claude 3.5 Sonnet模型&#xff01; 用官网的话就是&#xff1a; 今天&#xff0c;我们推出了 Claude 3.5 Sonnet&#xff0c;这是我们即将推出的 Claude 3.5 型号系列中的第一个版本。Claude 3.5 Sonne…

vscode 打开远程bug vscode Failed to parse remote port from server output

vscode 打开远程bug vscode Failed to parse remote port from server output 原因如图&#xff1a; 解决&#xff1a;

02 Git环境搭建

第2章&#xff1a;Git环境搭建 一、Git下载和安装 ​ 官网&#xff1a;Git (git-scm.com) 一&#xff09;安装主程序 ​ 准备安装包&#xff0c;双击安装 ​ 开始安装 ​ 选择安装位置 ​ 选择需要安装的组件&#xff08;默认&#xff09; ​ 选择文件夹菜单 ​ 选择编辑器&…

Word参考文献交叉引用

前言 Word自带交叉引用功能&#xff0c;可在正文位置引用文档内自动编号的段落&#xff0c;同时创建超链接&#xff0c;适用于参考文献的引用。使用此方法对参考文献进行引用后&#xff0c;当参考文献的编号发生变化时&#xff0c;只需要更新域即可与正文中的引用相对应。下文…

sysbench测试CPU

版本&#xff1a;sysbench1.1 简介 sysbench 对 CPU 测试的原理是通过创建多个线程&#xff0c;并让它们执行计算密集型任务来测试 CPU 性能。它会记录每个线程执行任务所需的时间&#xff0c;并计算出整个测试过程的平均值、最小值和最大值&#xff0c;甚至输出直方图展示延迟…

SpringBoot下的定时魔法:揭秘@Scheduled注解的无限可能

在这个快节奏的时代&#xff0c;自动化与定时任务成为了提升效率的不二法门。而在Java的Spring Boot框架中&#xff0c;Scheduled注解就像是一位精通时间魔法的巫师&#xff0c;悄无声息地让你的应用按部就班地执行着各种定时任务。今天&#xff0c;就让我们一起揭开它的神秘面…

【Qt 常用控件】带你进一步了解常用控件

文章目录 1. Push Button2. Radio Button3. Check Box4. 显示类控件5. 输入类控件 QLineEdit5.1 正则表达式5.2 验证器 - 验证手机号5.3 验证两次密码是否一致5.3 明文的显示密码 1. Push Button &#x1f427;给按钮设置图标 &#x1f427; 注意&#xff1a;设置快捷键需要在…

【运维资料大全】运维全套资料整理(word原件完整版)

信息安全类、运维类资料整合&#xff1a; 1. 等保测评模板 2. 安全检查表&#xff08;IDS&#xff0c;Linux&#xff0c;数据库&#xff0c;Tomcat&#xff0c;防火墙等&#xff09; 3. 服务器安全巡检表 4. 网络定向攻击风险分析表 5. 应用系统常规检测表 6. 企业漏洞管理50个…

Web开发:卡片翻转效果(HTML、CSS)

目录 一、实现效果 二、完整代码 三、实现过程 1、页面结构 2、初始样式 3、翻转效果 4、图片大小问题 一、实现效果 如下图所示&#xff0c;当鼠标移入某个盒子&#xff0c;就反转这个盒子&#xff0c;并显示其背面的内容——卡片翻转效果&#xff1b; 卡片翻转效果 二…

【HarmonyOS】HarmonyOS NEXT学习日记:二、ArkTs语法

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;二、ArkTs语法 众所周知TS是JS的超集,而ArkTs则可以理解为是Ts的超集。他们的基础都基于JS&#xff0c;所以学习之前最好就JS基础。我的学习重点也是放在ArkTs和JS的不同点上。 文章主要跟着官方文档学习&#xff0c;跳过了一…

Golang | Leetcode Golang题解之第234题回文链表

题目&#xff1a; 题解&#xff1a; func reverseList(head *ListNode) *ListNode {var prev, cur *ListNode nil, headfor cur ! nil {nextTmp : cur.Nextcur.Next prevprev curcur nextTmp}return prev }func endOfFirstHalf(head *ListNode) *ListNode {fast : headslo…