[算法应用]关键路径算法的简单应用

news2024/11/20 3:33:49

(0)免责声明:

算法和数据结构都是我自己写的,为了提交这次的作业,所以把去年写过的算法重新翻新了一下,数据结构也简单整理了一下,重新放上来了.

整个程序是可以顺利跑通的,同学们可以用代码检测一下自己的结果对不对,切勿抄袭.

(真的不想手推关键路径了....真的....不过复习整个算法,还有重新编写数据结构确实花了点时间)

(1)问题描述

很简单,就是要est和lst,还有关键路径

(在下面的代码中,我们习惯性地称呼为etv和ltv)

数据分析,一共14条边,10个点,按照顺序从0开始算起,按照起点,终点,权重三要素,可以把数据划分为

0 1 3
0 2 6
0 3 10
1 4 13
4 6 2
2 5 4
3 5 8
5 6 3
5 7 20
5 8 4
8 9 12
7 9 10
8 7 1
6 9 7

(2)代码原理分析/算法逻辑

代码的实现逻辑是这样的

1.首先按照拓扑结构进行的,按照拓扑顺序遍历每个点,如点A,到下流点B这一路径上,如果B的最早开始时间早于A的最早时间加上A-B需要的时间,那么就把B的最早开始时间延后.

2.然后按照逆拓扑结构进行,如果A的最晚开始时间+A->B需要的时间晚于B的最晚开始时间,那么就把A的最晚开始时间往前移动

3.关键路径就是,A的最早开始时间+AB需要的时间=B的最晚开始时间,那么这条就是关键路径之一

(3)数据存储结构的实现

//图结构已经储存完毕;(graph为邻接表进行存储)
class Node {
public:
    int num;
    int weight;     //路径的消耗时间保存在终点上,视为路径徐娅萍的时间
    Node* next;
    Node(int a) { num = a; };
};
class headNode {
public:
    int length = 0;
    Node* point=NULL;
    int in, out = 0;
};
class graph {
public:
    headNode arr[20];
    int NodeNum, EdgeNum = 0;
};
void createGraph(graph& Graph) {
    int edge, point,start,end,weight;
    cout << "请输入边数 和 点数" << endl;
    cin >> edge >> point;
    Graph.EdgeNum = edge;
    Graph.NodeNum = point;
    for (int i = 0; i < point; i++) {
        Graph.arr[i] = headNode();
    }
    cout << "请按照顺序输入起点,终点,权重" << endl;
    for (int i = 1; i <= edge; i++) {
        cin >> start >> end >> weight;
        Graph.arr[start].out++;//出度+1
        Graph.arr[end].in++;//入度+1
        Node* temp = new Node(end);
        temp->weight = weight;//赋予权重
        temp->next = Graph.arr[start].point;
        Graph.arr[start].point = temp;//头插法插入
    }
}
//图结构已经储存完毕;

(4)完整代码

//关键路径算法
//受到学妹的启发,终于明白这个最短是什么意思了
//最短并非指的是从起点到终点的最短距离(事实上这个也能求,不过理论上不行)
//关键路径的时间加起来,其实是完成所有任务需要的最短时间(默认任务是可以并发完成的)
//感谢来自隔壁实验室的22级同学的讨论和提示
int etv[20];//最早开始时间
int ltv[20];//最晚开始时间
int top = 0;//指针
int Stack[20];//这是储存用到的栈,或者说是数组

//关键路径算法的实现
void topuGraph(graph& Graph) {
    stack<int> stack2;
    for (int i = 0; i < Graph.NodeNum; i++) {
        if (Graph.arr[i].in == 0)stack2.push(i);  //先把入度为0的点压入栈中
        etv[i] = 0;                               //设置每个点的最早开始时间为0
    }
    while (!stack2.empty()) {
        int temp = stack2.top();                  //获取一个出发点,并且弹出来,然后按照拓扑排序,保存一个信息
        stack2.pop();
        Stack[top++] = temp;
        Node* point = Graph.arr[temp].point;      //然后开始对点的所有下游点进行遍历
        while (point) {
            if (--Graph.arr[point->num].in == 0) { //先处理这个点作为入度的情况,也就是对下面的下游点们剔除这个点的影响
                stack2.push(point->num);
            }
            if (etv[point->num]<etv[temp]+point->weight) {//修改最早数值    : 如果这个点的最早开始时间,早于上一个任务的开始时间+完成需要时间
                etv[point->num] = etv[temp] + point->weight;   //就适当延后这个点的开始时间
            }
            point = point->next;
        }
    }
}


void keyRoad(graph& Graph) {
    for (int i = 0; i < Graph.NodeNum; i++) {
        ltv[i] = etv[Graph.NodeNum-1];              //给每个点都设置一个最晚的.或者足够大的最晚开始时间
    }
    while (top >= 0) {                              //拓扑排序从后往前(按照之前的顺序)
        int temp = Stack[top--];
        Node* point = Graph.arr[temp].point;       //同样是遍历这个点所有的子点
        while (point) {                            //如果最晚开始时间晚于子点的最晚开始时间-子点需要完成的时间,那么就把最晚开始时间往前调
            if (ltv[temp] > ltv[point->num] - point->weight) {
                ltv[temp] = ltv[point->num] - point->weight;
            }
            point = point->next;
        }
    }
    //在邻接表中寻找关键路径,
    //如果一个点的最早开始时间+这个点需要的时间恰好为下一个点开始的最早时间,那么这个路径就一定是关键路径了
    int ete, lte = 0;
    for (int i = 0; i < Graph.NodeNum; i++) {
        Node* point = Graph.arr[i].point;
        while (point) {
            ete = etv[i];
            lte = ltv[point->num]-point->weight;
            if (ete == lte) {
                cout<<"关键路径为"<<endl;
                cout << (char)(i+65) << "--->" << (char)(point->num+65) <<"("<<point->weight<<")" << endl;
            }
            point = point->next;
        }
    }
}


int main(){
    graph g;
    createGraph(g);
    topuGraph(g);
    keyRoad(g);
    cout<<"每个点的最早,最晚开始时间分别为:"<<endl;
    for (int i = 0; i < g.NodeNum; ++i) {
        cout<<(char)(i+65)<<"  最早开始时间为:"<<etv[i]<<", 最晚开始时间为:"<<ltv[i]<<endl;
    }
}

(5)跑通的最后结果

关键路径为
A--->D(10)
关键路径为
D--->F(8)
关键路径为
F--->H(20)
关键路径为
H--->J(10)
每个点的最早,最晚开始时间分别为:
A  最早开始时间为:0, 最晚开始时间为:0
B  最早开始时间为:3, 最晚开始时间为:26
C  最早开始时间为:6, 最晚开始时间为:14
D  最早开始时间为:10, 最晚开始时间为:10
E  最早开始时间为:16, 最晚开始时间为:39
F  最早开始时间为:18, 最晚开始时间为:18
G  最早开始时间为:21, 最晚开始时间为:41
H  最早开始时间为:38, 最晚开始时间为:38
I  最早开始时间为:22, 最晚开始时间为:36
J  最早开始时间为:48, 最晚开始时间为:48

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

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

相关文章

2023-10-06 LeetCode每日一题(买卖股票的最佳时机含手续费)

2023-10-06每日一题 一、题目编号 714. 买卖股票的最佳时机含手续费二、题目链接 点击跳转到题目位置 三、题目描述 给定一个整数数组 prices&#xff0c;其中 prices[i]表示第 i 天的股票价格 &#xff1b;整数 fee 代表了交易股票的手续费用。 你可以无限次地完成交易&…

C++转换函数

什么是转换函数? C转换函数是一种特殊的成员函数&#xff0c;用于将一个类的对象转换为另一个类型。它是通过在类中定义特定的函数来实现的。 转换函数的用途&#xff1a; 类型转换&#xff1a;转换函数可以将一个类的对象从一种类型转换为另一种类型。这样可以方便地在不同…

前端还不会低代码?快来学习这5个开源的前端低代码项目

GoView GoView是一个开源项目&#xff0c;其技术栈基于Vue3、TypeScript4、Vite2、NaiveUI、ECharts5和Axios。该项目通过Vue组件实现数据中动态刷新渲染&#xff0c;且其内部图表可以自由替换。 项目地址&#xff1a; https://gitee.com/dromara/go-view 以下是GoView开源项目…

【C++设计模式之备忘录模式:行为型】分析及示例

简介 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它用于保存和恢复对象的状态。备忘录模式通过将对象的状态封装成一个备忘录&#xff08;Memento&#xff09;&#xff0c;并将备忘录保存在一个管理者&#xff08;Caretaker&#xff…

结构化面试 --- 介绍 + 人际关系

目录 一、介绍 1、认识考试 2、认识考官 3、认识对手 4、认识考场 5、认识规则 6、如何备考 二、人际关系 练习题 第一题&#xff08;换岗&#xff09; 第二题&#xff08;办法&#xff09; 第三题&#xff08;相处&#xff09; 第四题 第五题 第六题 …

初级数值计算理论总结

本文用于总结复习与研究生面试 一问&#xff0c;小伙子会不会数值计算啊一答&#xff1a;会二问&#xff1a;哦&#xff0c;讲讲看二答&#xff1a;讲不出来三问&#xff1a;...... 数值求根 二分法Jacobi 迭代法 Jacobi 迭代改进算法&#xff08;事后加速法&#xff09;&#…

[架构之路-228]:目标系统 - 纵向分层 - 计算机硬件与体系结构 - 硬盘存储结构原理:如何表征0和1,即如何存储0和1,如何读数据,如何写数据(修改数据)

目录 前言&#xff1a; 一、磁盘的盘面组成 1.1 磁盘是什么 ​编辑1.2 磁盘存储介质 1.3 磁盘数据的组织 1.3.1 分层组织&#xff1a;盘面号 1.3.2 扇区和磁道 1.3.3 数据 1.3.4 磁盘数据0和1的存储方式 1.3.5 磁盘数据0和1的修正方法 1.3.6 磁盘数据0和1的读 二、…

【AI视野·今日Robot 机器人论文速览 第四十九期】Fri, 6 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Fri, 6 Oct 2023 Totally 29 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;ContactGen, 基于生成模型的抓取手势生成&#xff0c;类人五指手。(from 伊利诺伊大学 香槟) 数据集&#xff1a;GRAB da…

多线程 - 定时器

多线程 - 定时器 定时器的背景知识 定时器 ~~ (就类似于定闹钟) 平时的闹钟,有两种风格: 指定特定时刻,提醒指定特定时间段之后,提醒 这里的“定时器”,不是提醒,而是执行一个实现准备好的方法/代码,它是开发中一个常用的组件,尤其是在网络编程的时候,使用浏览器上网,打开…

【立体视觉(五)】之立体匹配与SGM算法

【立体视觉&#xff08;五&#xff09;】之立体匹配与SGM算法 一、立体匹配一&#xff09;基本步骤二&#xff09;局部立体匹配三&#xff09;全局立体匹配四&#xff09;评价标准1. 均方误差(RMS)2. 错误匹配率百分比(PBM) 二、半全局(SGM)立体匹配一&#xff09;代价计算二&a…

雷达干扰和烧穿范围简介

一、干扰信号比 J/S或J-to-S是从目标发射的干扰信号接收的功率(J)与从目标的雷达反向散射接收的功率的比率。 二、烧穿范围 通过电子攻击(J)可以首先检测到目标回波信号(S)的雷达到目标的距离。 三、自保护干扰 也称为主瓣干扰(雷达回波源和干扰机并置)。 烧穿范围…

汽车驾驶任务的隐马尔可夫模型识别方法研究

汽车驾驶任务的隐马尔可夫模型识别方法研究 一、Introduction 自动驾驶汽车经过了几十年的发展&#xff0c;是目前国内外汽车行业中的重要研究方向。自 动驾驶汽车的智能化需要车辆能够有类“人”的行为&#xff0c;在决策策略上可以满足人的心理 需求。人在驾驶过程中&#…

Aasee Api开放平台上线啦!

使用方法 首先介绍使用方法&#xff0c;只需导入一个SDK即可使用实现调用第三方的接口&#xff0c;那如何导入SDK呢&#xff0c;目前jar已经上传至maven中心仓库可直接引入到pom文件中使用&#xff0c;下面是例子&#xff1a; <dependency><groupId>io.github.Aa…

攻防世界-T1 Training-WWW-Robots

文章目录 步骤1步骤二结束语 步骤1 看到文本——>提取有效信息——>利用有效信息 文本&#xff1a;In this little training challenge, you are going to learn about the Robots_exclusion_standard. The robots.txt file is used by web crawlers to check if they …

jar 命令启动java 指定配置文件路径 jar如何启动

一、各种启动方式 1.java -jar # 例子 java -jar test.jar 1. 2. 这是最简单的启动方式&#xff0c;同时弊端也是很多的。 弊端1&#xff1a;exit 退出终端会导致java进程中断。 弊端2&#xff1a;ctrlc 退出启动展示页会导致java进程中断。 弊端3&#xff1a;直接关闭终端会…

FREERTOS内容解惑与综合应用(基于STM32F103)

本文基础内容参考的是正点原子的FREERTOS课程。 这是基于HAL库的 正点原子手把手教你学FreeRTOS实时系统 这是基于标准库的 正点原子FreeRTOS手把手教学-基于STM32 基础知识&#xff0c;直接参考正点原子《FreeRTOS开发指南V1.1》基于标准库的&#xff0c;此处不再赘述。 本文…

【Java 进阶篇】HTML介绍与软件架构相关知识详解

HTML&#xff08;Hypertext Markup Language&#xff09;是一种用于创建网页的标记语言。它是互联网上信息传递和展示的基础&#xff0c;无论是在浏览器中查看网页还是在移动设备上浏览应用程序&#xff0c;HTML都扮演着关键角色。本文将向您介绍HTML的基础知识&#xff0c;并探…

踩大坑ssh免密登录详细讲解

目 录 问题背景 环境说明 免密登录流程说明 1.首先要在对应的用户主机名的情况下生成密钥对&#xff0c;在A服务器执行 2.将A服务器d公钥拷贝到B服务器对应的位置 3.在A服务器访问B服务器 免密登录流程 0.用户说明 1.目前现状演示 2.删除B服务器.ssh 文件夹下面的…

多普勒频率相关内容介绍

图1 多普勒效应 1、径向速度 径向速度是作用于雷达或远离雷达的速度的一部分。 图2 不同的速度 2、喷气发动机调制 JEM是涡轮机的压缩机叶片的旋转的多普勒频率。 3、多普勒困境 最大无模糊范围需要尽可能低的PRF&#xff1b; 最大无模糊速度需要尽可能高的PRF&#xff1b…

什么是TF-A项目的长期支持?

安全之安全(security)博客目录导读 问题&#xff1a;Trusted Firmware-A社区每六个月发布一次代码。然而&#xff0c;对于生产中的平台&#xff0c;该策略在维护、重要软件修复的向后兼容性、获得最新的安全缓解措施和整体产品生命周期管理方面不具备可扩展性。 开源软件项目&…