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

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

前面介绍了图的应用——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");elseprintf("%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


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

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • CSS3 教程
  • Flutter 中的基本数据类型:num、int 和 double
  • 极狐GitLab Git LFS(大文件存储)如何管理?
  • JSP静态包含与动态包含的区别
  • 基于 Go1.19 的站点模板爬虫:构建与实战
  • IDEA的常见代码模板的使用
  • 数据仓库的一致性维度
  • 如何在 Mac 上下载安装植物大战僵尸杂交版? 最新版本 2.2 详细安装运行教程问题详解
  • AWS服务器购买:如何选择合适的AWS云服务器
  • 大语言模型-检索测评指标
  • Docker 修改默认镜像的存储位置
  • 【考研数学】线代满分经验分享+备考复盘
  • 【Qt】事件处理
  • 图论建模技巧搜集
  • Matlab学习笔记1
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • CentOS从零开始部署Nodejs项目
  • Computed property XXX was assigned to but it has no setter
  • idea + plantuml 画流程图
  • jquery ajax学习笔记
  • Js基础知识(一) - 变量
  • Lsb图片隐写
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webpack+react项目初体验——记录我的webpack环境配置
  • 关于使用markdown的方法(引自CSDN教程)
  • 记一次用 NodeJs 实现模拟登录的思路
  • 聚簇索引和非聚簇索引
  • 免费小说阅读小程序
  • 如何在GitHub上创建个人博客
  • 使用common-codec进行md5加密
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • ​比特币大跌的 2 个原因
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • #define
  • (145)光线追踪距离场柔和阴影
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (八十八)VFL语言初步 - 实现布局
  • (第27天)Oracle 数据泵转换分区表
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (一)80c52学习之旅-起始篇
  • (一)Linux+Windows下安装ffmpeg
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)负载均衡,回话保持,cookie
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET命令行(CLI)常用命令
  • .net网站发布-允许更新此预编译站点
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @font-face 用字体画图标
  • @KafkaListener注解详解(一)| 常用参数详解