图论之关键路径讲解

回顾所需知识:

拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

拓扑排序对应施工的流程图具有特别重要的作用,它可以决定哪些子工程必须要先执行,哪些子工程要在某些工程执行后才可以执行。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。

通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网

一个AOV网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行(对于数据流来说就是死循环)。在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。

AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。

拓扑排序的实现步骤※

  1. 在有向图中选一个没有前驱的顶点并且输出
  2. 从图中删除该顶点和所有以它为尾的弧 (白话就是:删除所有和它有关的边)
  3. 重复上述两步,直至所有顶点输出,循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列。

因此,也可以通过拓扑排序来判断一个图是否有环。

AOE网介绍

AOE-网只是比AOV-网多了一个边的权重,而且AOV-网一般是设计一个庞大的工程各个子工程实施的先后顺序,而我们的AOE-网就是不仅仅关系整个工程中各个子工程的实施的先后顺序,同时也关系整个工程完成最短时间。

通常在AOE网中列出完成预定工程计划所需要进行的活动,每个活动计划完成的时间,要发生哪些事件以及这些事件与活动之间的关系,从而可以确定该项工程是否可行,估算工程完成的时间以及确定哪些活动是影响工程进度的关键

AOE网特点

AOE-网还有一个特点就是:只有一个起点(入度为0的顶点)和一个终点(出度为0的顶点),并且AOE-网有两个待研究的问题:
1、完成整个工程需要的时间
2、哪些活动是影响工程进度的关键

关键路径介绍

关键路径:AOE-网中,从起点到终点最长的路径的长度(长度指的是路径上边的权重和)
关键活动
假设起点是vo,则我们称从v0到vi的最长路径的长度为vi的最早发生时间
同时,vi的最早发生时间也是所有以vi为尾的弧所表示的活动的最早开始时间
使用e(i)表示活动ai最早发生时间,除此之外,我们还定义了一个活动最迟发生时间,使用l(i)表示,不推迟工期的最晚开工时间。我们把e(i)=l(i)的活动ai称为关键活动,因此,这个条件就是我们求一个AOE-网的关键路径的关键所在了。

求关键路径的步骤

  1. 输入顶点数和边数,已经各个弧的信息建立图
  2. 从源点v1出发,令ve[0]=0;按照拓扑序列往前求各个顶点的ve。如果得到的拓扑序列个数小于网的顶点数n,说明我们建立的图有环,无关键路径,直接结束程序
  3. 从终点vn出发,令vl[n-1]=ve[n-1],按逆拓扑序列,往后求其他顶点vl值
  4. 根据各个顶点的ve和vl求每个弧的e(i)和l(i),如果满足e(i)=l(i),说明是关键活动。

代码实现

例题
SDUT2498

#include<bits/stdc++.h>using namespace std;const int M = 5e4 + 5;struct N {int in, out, weight;
}edge[M];               //用结构体表示边int node[M];           //记录经过的节点
int distant[M];         //记录最长路径
int degree_in[M];       //记录每个点的入度   目的是寻找源点(没有入度的点)
int sourcepoint;        //源点    void bellman(int point_number, int edge_number) {memset(node, 0, sizeof(node));memset(distant, 0, sizeof(distant));for (int k = 2; k <= point_number; k++) {     //除去源点,只需要进行(点的数量-1)次求值int flag = 0;                                //每次找下一个点的时候都会重置flagfor (int i = 1; i <= edge_number; i++) {     //动态规划,找K次,每次都更新源点的权值,最后源点的权值最大,输出的就是最大路径if ((distant[edge[i].in] < distant[edge[i].out] + edge[i].weight) || ((distant[edge[i].in] == distant[edge[i].out] + edge[i].weight) && (edge[i].out < node[edge[i].in]))) {distant[edge[i].in] = distant[edge[i].out] + edge[i].weight;   //把权值放到每条边的起点上,最后输出源点的权值node[edge[i].in] = edge[i].out;flag = 1;}}if (flag == 0) {                           //如果flag没更新,说明循环每条边的时候找不到比原来的权值更大的路径了,跳出循环即可break;                                    //这时候源点处已经找到了最大权值}}printf("%d\n", distant[sourcepoint]);          //跳出循环后,输出最终结果while (node[sourcepoint] != 0) {printf("%d %d\n", sourcepoint, node[sourcepoint]);sourcepoint = node[sourcepoint];}
}int main() {int point_number, edge_number;int sv, ev, w;while (~scanf("%d%d", &point_number, &edge_number)) {memset(edge, 0, sizeof(edge));              //多组数据输入时 初始化很重要memset(degree_in, 0, sizeof(degree_in));for (int i = 1; i <= edge_number; i++) {scanf("%d%d%d", &sv, &ev, &w);edge[i].in = sv;        //每条边的入度、出度、权重edge[i].out = ev;edge[i].weight = w;degree_in[ev]++;      //每个点的入度}for (int i = 1; i <= point_number; i++) {       //寻找源点if (degree_in[i] == 0) {                        //入度为零的点为源点sourcepoint = i;}   }bellman(point_number, edge_number);}return 0;
}

看不懂的可以自取视频理解,多看两遍就差不多了

关键路径 详解 (前置知识:拓扑排序)相关推荐

  1. 有向无环图—关键路径详解(最通俗易懂的版本)【数据结构】

    文章目录 有向无环图 拓扑排序 AOV-网 AOE-网 关键路径的概念 事件的最早/晚开始时间 事件和活动的区分 活动的最早/晚开始时间 有向无环图 拓扑排序 AOV-网 由于有向无环图可以用一种自然 ...

  2. ad19pcb设置恢复默认_电脑主板BIOS设置详解BIOS知识大全

    电脑主板BIOS设置详解-BIOS知识大全 什么是电脑BIOS,一般电脑主板都设置了电脑开机后一直按着Del键即可进入BIOS. 系统开机启动 BIOS,即微机的基本输入输出系统(Basic Inpu ...

  3. 分布式系统详解--基础知识(概论)

                           分布式系统详解--基础知识(概论) 一. 引言         由于网上介绍的分布式的系统讲解并没有多少,所以在这儿就希望可以写一套系统的分布式的详解,未 ...

  4. 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

    养成习惯,先赞后看!!! 你的点赞与关注真的对我非常有帮助.如果可以的话,动动手指,一键三连吧!!! 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 前言 这是十大经典排序算法详解的最后一篇了. ...

  5. 会排序吗_洗牌算法详解:你会排序,但你会打乱吗?

    预计阅读时间: 8 分钟 我知道大家会各种花式排序,但是如果叫你打乱一个数组,你是否能做到胸有成竹?即便你拍脑袋想出一个算法,怎么证明你的算法就是正确的呢?乱序算法不像排序算法,结果唯一可以很容易检验 ...

  6. python数组排序sort_详解python中sort排序使用

    1.前言 昨天一学妹问我一个关于python的问题,当时在外忙碌,没时间细看.今天看一下,咋一看我还真的不知道这个问题,bookinfo.sort(reverse=True ,key=lambda x ...

  7. c语言动画原理,动画详解十大经典排序算法(C语言版)

    排序算法是程序员必备的基础知识,弄明白它们的原理和实现很有必要.本文中将通过非常细节的动画展示出算法的原理,配合代码更容易理解. 概述 由于待排序的元素数量不同,使得排序过程中涉及的存储器不同,可将排 ...

  8. OFDM正交频分复用——详解——5G-LTE知识必备

    这篇文章写得很赞,本想上自己的仿真笔记,看到这篇文章,还是... 原文:<给"小白"图示讲解OFDM的原理> 以下为整理内容,添加部分笔记: 章节一:时域上的OFDM ...

  9. java 排序方法详解_java中关于排序方式的实例讲解

    冒泡排序 特点:效率低,实现简单 思想(从小到大排):每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有元素.这只是冒泡排序的一种,当然也可以从后往前排.publi ...

最新文章

  1. Java ResultSet如何检查是否有任何结果
  2. C语言 - sizeof和strlen的区别
  3. 文明重启服务器维护怎么卡进去,文明重启更新之后进不去,具体玩法介绍
  4. Java13的API_JAVA基础--JAVA API常见对象(其他API)13
  5. 【itext学习之路】--4.给pdf增加文本水印和图片水印
  6. 3d打印主要的切片参数类型_3D打印机切片参数详情说明
  7. ad怎么批量改元器件封装_AD6.8的原理图中如何批量修改封装?
  8. 查看linux端口对应的进程id
  9. Linux内存管理:ARM64体系结构与编程之cache(2):cache一致性
  10. java `Charset`或者`StandardCharsets`
  11. 老生常谈的一个问题,转行学习编程,是自学还是报班
  12. 魔兽世界各服务器显示版本,魔兽7.1各服通用界面AltzUI
  13. abb机器人指令手册_ABB机器人加速度设置
  14. 【定制开发】【M3】基于Python+pygame实现的人机AI对战五子棋游戏(保姆级入门讲解)
  15. 牛牛卡牌游戏 javascript
  16. excel多个工作表合并怎么操作
  17. PVC地板IMO船舶防火测试认证注意事项
  18. My SQL中PK、NN、UQ、BIN、UN、ZF、AI、G所代表的意义
  19. 地图可视化绘制 | R-tanaka/metR包 绘制3D阴影效果地图
  20. 主wifi旁零距离添加AP路由器

热门文章

  1. [Swift通天遁地]七、数据与安全-(6)管理文件夹和创建并操作文件
  2. 导致电脑显示屏字体模糊的原因
  3. from..import 语句
  4. Explaining Knowledge Distillation by Quantifying the Knowledge
  5. Git关于commit的操作,修改message,合并commit,撤销commit
  6. 认识IE6的隐私让上网冲浪更安全(转)
  7. windows phone 网络开发三部曲(一)各种包的各种抓法
  8. Codeforces Round #808 (Div. 1)(A~C)
  9. 2021年目标,我打算这样去实现
  10. 无线电能传输 wpt 磁耦合谐振 过零检测 基于二极管整流的无线电能传输设计 基于同步整流的无线电能传输设计