图的应用4.0-----关键路径(AOE网)

目录

前言

AOE网

1.基本概念

2.应用

关键路径

1.算法理论

2.代码实现(C/C++)


前言

        前面学习了图AOV网的应用,即拓扑排序,那这一期我们学习AOE网的应用,这是一个图的一个很广泛问题,也就是关键路径。那什么是关键路径呢?下面就一起来看看。

 数据结构----图的应用四部曲
最小生成树问题:图的应用1.0-----最小生成树问题-CSDN博客
最短通路问题(Djkstra算法):图的应用2.0-----最短通路问题(Dijkstra和Floyd算法)-CSDN博客

拓扑排序:图的应用3.0-----拓扑排序-CSDN博客
关键路径算法:图的应用4.0-----关键路径(AOE网)-CSDN博客

AOE网

1.基本概念

        把工程计划表示为边表示活动的网络,即AOE网用顶点表示事件,弧表示活动,弧的权表示活动持续时间。

        事件表示在它之前的活动已经完成,在它之后的活动可以开始

 如图所示,这就是一个AOE网的问题

任意应该AOE网都有一个起点和终点,那这里就称作为源点和汇点。 

源点与汇点

源点:入度为0的点,表示一个工程的开始。

汇点:出度为0的点,表示一个工程的结束。

2.应用

对于AOE网,我们关心两个问题

  1. 完成整项工程至少需要多少时间?
  2. 哪些活动是影响工程进度的关键?

AOE网可以很好的表示一项工程或者项目经历的流程和时间,那现在提出一个问题:如何从起点到终点经历过的总时间最长呢?(完成这个工程需要的最长时间)

这里就要用到关键路径的算法了,下面我们就来看看关键路径是怎么q求的。

关键路径

关键路路径-----路径长度最长的路径
路径长度------路径上各活动持续时间之和。

1.算法理论

 以这个图为示例,下面要弄懂4个数组数据的值

1.  ve(vj)------表示事件 vj的最早发生时间

         例: ve(v1) = 0 ve(v2) = 30

2.vl(vj)-----表示事件 vj 的最迟发生时间

         例: vl(v4) = 165

3.e(i)-----表示活动ai的最早开始时间

        例:e(a3) = 30

4.l(i)-----表示活动ai 的最迟开始时间

         例: l(a3) = 120

l(i) - e(i)-表示完成活动 ai 的时间余量。 例: (3) - e(3) = 90

关键活动

关键活动关键路径上的活动,即 l(i) == e(i) (即 l(i) - e(i) ==0 ) 的活动

以上4个量的关系: 

1.如何找l)== e(i)的关键活动?

设活动 ai 用弧 <j,k> 表示,其持续时间记为: Wj,k

则有: (1) e(i) = ve(j)

         (2) l(i) = vl(k) - Wj, k

2.如何求 ve(j)和 vl(j) ?

(1) 从 ve(1)=0开始向前递推

        ve(j) = Max{ve(i) + Wij}, < i,j >属于T, 2 <=j <=n

        其中T是所有以i为头的弧的集合。

(2)从 vl(n)= ve(n)开始向后递推

        vl(i) = Min{vl(j) - Wij}, < i, j >属于S, 1<=i<=n -1

        其中 S 是所有以i为尾的弧的集合。

注意:最短路径与最小生成树不同,路径上不一定包含 n个顶点,也不定包含 n-1条边 

求解过程,以下图为案例求解ve、vl、e、和l数组。

求关键路径步骤:

  1. 求 ve(i)、vl(j)
  2. 求e(i)、l(i)
  3. 计算 l(i) - e(i),如果值为0那就是关键路径中的一条路径
  4. 套用以下公式即可

求得的ve和vl如图所示:

求得的e和l,如图所示:

2.代码实现(C/C++)

邻接矩阵图的结构体:

#define Maxint 32767
#define Maxnum 100//最大顶点数//数据类型
typedef struct datatype {char id[10];//……
}
ElemType;
//图的邻接数组
typedef struct graph {ElemType vexs[Maxnum];//图数据int matrix[Maxnum][Maxnum];//二维数组矩阵int vexnum;//点数int arcnum;//边数
}Graph;

关键路径算法代码: 

//获取入度为0的起始点下标
int in_degree0(Graph G) {int* sum_degree = (int*)malloc(sizeof(int) * G.vexnum);memset(sum_degree, 0, sizeof(int) * G.vexnum);for (int x = 0; x < G.vexnum; x++) {for (int y = 0; y < G.vexnum; y++) {if (G.matrix[y][x] != 0 && G.matrix[y][x] != Maxint) {sum_degree[x]++;}}}for (int i = 0; i < G.vexnum; i++) {if (sum_degree[i] == 0) {free(sum_degree);sum_degree = NULL;return i;}}}
//获取出度为0的交汇点下标
int out_degree0(Graph G) {int* sum_degree = (int*)malloc(sizeof(int) * G.vexnum);memset(sum_degree, 0, sizeof(int) * G.vexnum);for (int x = 0; x < G.vexnum; x++) {for (int y = 0; y < G.vexnum; y++) {if (G.matrix[x][y] != 0 && G.matrix[x][y] != Maxint) {sum_degree[x]++;}}}for (int i = 0; i < G.vexnum; i++) {if (sum_degree[i] == 0) {free(sum_degree);sum_degree = NULL;return i;}}
}//队列的结构体
typedef struct q {int prev;//上一个顶点下标int next;//下一个顶点下标
}Queue;//边的结构体  起点 长度 终点
typedef struct e {int begin_index;//这个边的起始点int e;//边长度int end_index;//这个边的终点
}E;//关键路径算法AOE
void Critical_path(Graph G) {//申请ve,vl,e,l的空间int* ve = (int*)malloc(sizeof(int) * G.vexnum);int* vl = (int*)malloc(sizeof(int) * G.vexnum);E* e = (E*)malloc(sizeof(E) * G.arcnum);int* l = (int*)malloc(sizeof(int) * G.arcnum);Queue* queue = (Queue*)malloc(sizeof(Queue) * G.vexnum);//01--处理vefor (int k = 0; k < G.vexnum; k++) {queue[k].prev = queue[k].next = -1;ve[k] = 0;}//对第一个数据处理int begin = in_degree0(G);//初始化int qu_count = 0;queue[qu_count].prev = queue[qu_count].next = begin;qu_count++;//后继处理while (qu_count) {//出队操作Queue pop = queue[0];//后继数据前移for (int d = 0; d < qu_count - 1; d++) {queue[d] = queue[d + 1];}qu_count--;//获取到出队顶点最早开始时间veint max = ve[pop.prev] + G.matrix[pop.prev][pop.next];if (ve[pop.next] <= max)ve[pop.next] = max;//把当前出队的顶点后继连接的顶点入队for (int j = 0; j < G.vexnum; j++) {if (G.matrix[pop.next][j] != 0 && G.matrix[pop.next][j] != Maxint) {queue[qu_count].next = j;queue[qu_count].prev = pop.next;qu_count++;}}}//02--处理vlint end = out_degree0(G);for (int k = 0; k < G.vexnum; k++) {queue[k].prev = queue[k].next = -1;vl[k] = ve[end];}//对第一个数据处理queue[qu_count].next = queue[qu_count].prev = end;qu_count++;while (qu_count) {//出队Queue pop = queue[0];//后继数据前移for (int d = 0; d < qu_count - 1; d++) {queue[d] = queue[d + 1];}qu_count--;//比较找到最小值赋予到vlint min = vl[pop.next] - G.matrix[pop.prev][pop.next];if (min <= vl[pop.prev])vl[pop.prev] = min;//把当前出队的顶点前面相连的顶点入队for (int i = 0; i < G.vexnum; i++) {if (G.matrix[i][pop.prev] != 0 && G.matrix[i][pop.prev] != Maxint) {queue[qu_count].prev = i;queue[qu_count].next = pop.prev;qu_count++;}}}//03--处理eint e_count = 0;for (int i = 0; i < G.vexnum; i++) {for (int j = 0; j < G.vexnum; j++) {if (G.matrix[i][j] != 0 && G.matrix[i][j] != Maxint) {e[e_count].begin_index = i;e[e_count].e = ve[i];//套用公式e[e_count].end_index = j;e_count++;}}}//04--处理lint l_count = 0;for (int i = 0; i < G.vexnum; i++) {for (int j = 0; j < G.vexnum; j++) {if (G.matrix[i][j] != 0 && G.matrix[i][j] != Maxint) {//套用公式l[l_count++] = vl[j] - G.matrix[i][j];}}}//输出结果printf("\nve数组结果:");for (int j = 0; j < G.vexnum; j++) {printf("%d ", ve[j]);}printf("\nvl数组结果:");for (int j = 0; j < G.vexnum; j++) {printf("%d ", vl[j]);}printf("\ne的结果:");for (int j = 0; j < G.arcnum; j++) {printf("%d ", e[j].e);}printf("\nl的结果:");for (int j = 0; j < G.arcnum; j++) {printf("%d ", l[j]);}printf("\n关键路径路线如下:\n");for (int j = 0; j < G.arcnum; j++) {if (e[j].e - l[j] == 0) {int start = e[j].begin_index;int end = e[j].end_index;printf("%s->%s %d\n", G.vexs[start].id, G.vexs[end].id, G.matrix[start][end]);}}//释放空间free(ve);free(vl);free(e);free(l);free(queue);ve = vl = e = l = queue = NULL;
}

测试结果:

以上就是本期的内容了,喜欢的话点个赞吧!

 分享一张壁纸:

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

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

相关文章

k8s中kubectl陈述式资源管理

目录 1、 理论 1.1、 管理k8s核心资源的三种基本方法 &#xff1a; 1.1.1陈述式的资源管理方法&#xff1a; 1.1.1.1、优点&#xff1a; 1.1.1.2、缺点&#xff1a; 1.1.2、声明式资源管理方法 1.1.3、GUI式资源管理方法 1.2、陈述式资源管理方法 2. 对资源的增、删、…

[推荐]Linux安装与配置虚拟机之虚拟机服务器坏境配置

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 一.操作系统 1. 简介 操作系统&#xff08;perating System&#xff0c;简称OS&#xff09;是一种系统软件…

决定放弃uniapp开发了,因为它实在是没有taro友好

被uniapp折腾了两天&#xff0c;实在是受不了它对vue3的支持和react的支持&#xff0c;可以这么说&#xff0c;uniapp完全没有支持vue3和react&#xff0c;这么说我觉得一点也不过分。相对于折腾了两天uniapp来讲&#xff0c;我使用taro只花了1个小时不到&#xff0c;就可以完美…

【java学习—八】单例设计模式(5)

文章目录 1. 相关概念2. 单例设计模式-饿汉式3. 单例设计模式-懒汉式4. 总结 1. 相关概念 单例&#xff1a;只有一个实例&#xff08;实例化对象&#xff09; 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的…

【鸿蒙软件开发】ArkTS通用事件

文章目录 前言一、点击事件1.1 基础介绍1.2 ClickEvent对象说明1.3 示例代码 二、触摸事件2.1 基础介绍2.2 ClickEvent对象说明2.3 示例代码 二、焦点事件2.2 基础介绍3.2 示例代码 总结 前言 在我们的ArkTS中有一些通用的事件&#xff0c;他们在所有的组件中都可以用&#xf…

网工内推 | 急招网工,思科、华为认证优先,法定节假日三薪

01 江苏臻云技术 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责落实数据中心机房日常网络监测及巡检任务&#xff1b; 2、负责数据中心网络设备日常监控、变更、维护、巡检&#xff1b; 3、负责日常巡检报告、故障维护报告、变更申请的文档的编制&#xff1b;…

玩转ChatGPT:批量下载Alphafold的蛋白pdb文件

一、写在前面 突发奇想&#xff0c;想批量下载Alphafold网站的蛋白pdb文件&#xff0c;后续再做个分子对接用。又不想手动下载&#xff0c;来求助CSDN和GPT。 二、CSDN白嫖基础代码 CSDN大神多&#xff0c;这不&#xff0c;找到一个&#xff1a;Alphafold批量下载蛋白的pdb文…

Win10+Ubuntu20.04双系统双硬盘(SSD+HDD)安装与启动

Win10Ubuntu20.04双系统双硬盘安装与启动 前言准备工作Step 1: 备份你的数据Step 2: 制作安装Ubuntu的磁盘分区若以方式2进行安装&#xff1a;若以方式3进行安装&#xff1a; Step 3: 下载ubuntuStep 4: 制作ubuntu启动U盘Step 5: 从U盘启动ubuntuStep 6: 安装ubuntuStep 7: 系…

洗衣行业在线预约小程序+前后端完整搭建教程

大家好哇&#xff0c;好久不见&#xff01;今天源码师父来给大家推荐一款洗衣行业在线预约的小程序&#xff0c;带有前后端的完整搭建教程。 目前&#xff0c;人们对生活品质的追求不断提高&#xff0c;但生活节奏却也不断加快。对品质的追求遇到了忙碌的生活节奏&#xff0c;…

将安全作为首要目标 — Venus 的现状和前景展望

DeFi 的全面爆发将上一轮牛市推向巅峰。在不断的演化中&#xff0c;DeFi 领域也产生了很多新兴的细分领域&#xff0c;比如收益聚合器、合成资产、各种 DeFi 收益工具&#xff0c;以及最近整个市场都在讨论的 RWA 等。 DeFi 在不断进化&#xff0c;不变的是&#xff0c;DEX 和借…

使用内网穿透本地MariaDB数据库,并实现在公网环境下使用navicat图形化工具

公网远程连接MariaDB数据库【cpolar内网穿透】 文章目录 公网远程连接MariaDB数据库【cpolar内网穿透】1. 配置MariaDB数据库1.1 安装MariaDB数据库1.2 测试局域网内远程连接 2. 内网穿透2.1 创建隧道映射2.2 测试随机地址公网远程访问3. 配置固定TCP端口地址3.1 保留一个固定的…

Django 注册及创建订单商品

注册功能的实现 user/views from rest_framework.generics import GenericAPIView from rest_framework.views import APIViewfrom apps.user.models import User from apps.user.serializers import UserSerializer from utils import ResponseMessage from utils.jwt_auth …

P1868 饥饿的奶牛

根据题意可以知道是一个动态规划&#xff0c;看完数据范围之后可以知道是一个线性DP。 解决方法有点类似于背包问题&#xff0c;枚举背包的每一个空间。 如果把坐标轴上每个点都看成一个块儿&#xff0c;只需要按顺序求出前 i 个块儿的最大牧草堆数&#xff0c;f[i] 就是前i的…

进一步了解视频美颜SDK:美颜SDK的技术原理

美颜技术在当今的数字世界中变得越来越流行&#xff0c;尤其是在视频直播、社交媒体和视频通话应用中。用户寻求通过美颜效果增强自己的外观&#xff0c;这种需求催生了众多美颜SDK&#xff08;软件开发工具包&#xff09;的出现。这些SDK使开发者能够轻松地将美颜功能集成到他…

注意力机制、Transformer模型、生成式模型、目标检测算法、图神经网络、强化学习、深度学习模型可解释性与可视化方法等详解

采用“理论讲解案例实战动手实操讨论互动”相结合的方式&#xff0c;抽丝剥茧、深入浅出讲解注意力机制、Transformer模型&#xff08;BERT、GPT-1/2/3/3.5/4、DETR、ViT、Swin Transformer等&#xff09;、生成式模型&#xff08;变分自编码器VAE、生成式对抗网络GAN、扩散模型…

【代码思路】2023mathorcup 大数据数学建模B题 电商零售商家需求预测及库存优化问题

各位同学们好&#xff0c;我们之前已经发布了第一问的思路视频&#xff0c;然后我们现在会详细的进行代码和结果的一个讲解&#xff0c;然后同时我们之后还会录制其他小问更详细的思路以及代码的手把手教学。 大家我们先看一下代码这一部分&#xff0c;我们采用的软件是Jupyte…

通过流量安全分析发现主机异常

主机异常分析在计算机系统中具有重要意义。以下是主机异常分析的几个关键点&#xff1a; 1、检测安全威胁&#xff1a;主机是计算机系统的核心组件&#xff0c;通过对主机异常进行分析&#xff0c;可以快速检测到潜在的安全威胁&#xff0c;如恶意软件、病毒感染、黑客入侵等。…

js中的Formdata数据结构

这里写目录标题 一、基本概念二、常用方法1.append(name, value)、set(name, value)2.get()、getAll()3.has(name)4.delete(name)5.keys(),values(),entries() 三、其他细节1.for of遍历2.转为对象3.结合 URLSearchParams 转为queryString 一、基本概念 FormData 提供了一种表…

p5.js画布操作实战:创建,绑定指定元素,动态调整大小,隐藏滚动条,删除画布

文章简介 之前在 《p5.js 光速入门》 里粗略讲过一下如何使用 p5.js 创建画布。 这次要介绍几个 p5.js 提供的画布相关的方法。 创建画布时的相关配置。让画布绑定指定元素。重置画布大小。删除画布。 学习本文前你需要具备一点 p5.js 的知识&#xff0c;想了解的请查看 《p…

【Java 进阶篇】Java Request 继承体系详解

在Java编程中&#xff0c;Request&#xff08;请求&#xff09;是一个常见的概念&#xff0c;特别是在Web开发中。Request通常用于获取来自客户端的信息&#xff0c;以便服务器能够根据客户端的需求提供相应的响应。在Java中&#xff0c;Request通常涉及到一系列类和接口&#…