技术标签: 数据结构
1.课程设计内容与要求
用字符文件提供数据建立AOE网络的存储结构。编写程序,计算并输出工程的最短完成时间。
实验目的:掌握图的存储结构;掌握图的拓扑排序算法以及AOE网络顶点最早开始时间的计算方法。
1.课程设计内容与要求
用字符文件提供数据建立AOE网络的存储结构。编写程序,计算并输出工程的最短完成时间。
实验目的:掌握图的存储结构;掌握图的拓扑排序算法以及AOE网络顶点最早开始时间的计算方法。
程序采用C++语言进行开发,完成用字符文件提供数据建立AOE网络的存储结构,计算并输出工程的最短完成时间。
程序使用邻接表结构来存储图数据结构,借助栈数据结构完成对图的正逆拓扑排序,并求出个顶点的最早开始时间和最晚开始时间,最后计算并输出工程的最短完成时间。
执行过程如下:
关于拓扑排序,先初始化两个存储int类型下标的栈,st用于存储入度为0的点,topOrder用于存储拓扑排序的顺序,先将所有入度为0的点存入st中,若栈st中存在入度为0的结点,则继续进行拓扑排序,从栈顶弹出一个图中的顶点,存入topOrder中,遍历该顶点的所有邻接点, 先使所有邻接点的入度减一(逻辑上做删除操作),判断入度是否为0,为0则压入栈st中,如果邻接点事件的的最早发生时间小于当前顶点事件的最早发生时间加上当前顶点到邻接点的权值,则将邻接点的最早发生时间更新为当前顶点事件的最早发生事件加上两点间活动持续时间。将栈topOrder中的元素依次弹出,获得拓扑排序的逆序列,求解last数组,初始化所有事件的最迟开始时间数组last为汇点的最早发生时间,获取栈顶元素并遍历当前顶点的所有临接点,如果邻接点事件的最晚发生时间大于当前顶点事件的最晚发生时间减去当前顶点到邻接点的权值,则将邻接点的最晚发生时间更新为当前顶点事件的最晚发生时间减去两点间活动持续时间。
求解关键路径,就是遍历当前顶点的邻接点,如果最早发生时间和最晚发生时间相同的话,说明当前活动是关键活动,则输出当前活动,并从p->adjVertex出发寻找下一个关键活动,当前顶点事件邻接点的最晚开始时间减去当前活动[u, p -> adjacencyVertex]的权值就是当前活动的最晚开始时间,求得一关建路径后退出。
创建链表结点的结构体ArcNode,
成员变量int adjVertex,为该弧所指向的顶点的位置,
int weight表示有向边的路径长度(权值),
struct ArcNode* nextArc;指向下一个和头结点存在有向边的链表结点。
创建顶点结点结构体VertexNode,
成员变量,char data 存储结点上的数据,
ArcNodePtr firstArc,指向该顶点结点的第一个链表结点。
2.创建ALGraph类
成员变量:AdjList vertexes,表示图,early数组记录每个事件的最早发生时间,last数组记录每个事件的最晚发生时间。vexNum表示图中顶点的数量,arcNum表示边的数量,minTime表示工程的最短完成时间。
再定义一系列相关的成员函数,
void addEdge(ALGraph* g, int u, int v, int w);
用头插法在编号为u, v的顶点间增加一条边。
void createALGraph(ALGraph* g);
从文件输入中创建邻接表存储的有向图。
void getInDegree(ALGraph* g, int* inDegree);
求图中每个顶点的入度。
void topOrder(ALGraph* g);
拓扑排序求early和last。
void getCriticalPath(ALGraph* g, int u, int& minTime);
求解关键路径。
void criticalPath(ALGraph* g);
求解最短完成时间。
3.输入文件test01.txt格式
9 11 (结点数 边数)
0 1 6 (结点序号, 邻接点, 有向边的权值)
......
7 8 4 (共9个)
4.输出在屏幕上的信息
early数组和last数组的值,关键路径与工程完成所需的最短时间。
getInDegree(g, inDegree);求每个顶点的入度数组inDegree,
for (int i = 0; i < g->vexNum; ++i)
if (!inDegree[i]) st.push(i);先将所有入度为0的点存入st中,
while (!st.empty()) { 若栈st中存在入度为0的结点,则继续进行拓扑排序,
int curVex = st.top();
topOrder.push(curVex);
st.pop();
遍历该顶点的所有邻接点
for (ArcNodePtr p = g->vertexes[curVex].firstArc; p != nullptr; p = p->nextArc) {
先使所有邻接点的入度减一(逻辑上做删除操作)
if (!(--inDegree[p->adjVertex]))
如果入度减一后该邻接点的入度为0,则加入栈st中作为下一次排序的起点
st.push(p->adjVertex);
如果邻接点事件的的最早发生时间小于当前顶点事件的最早发生时间加上当前顶点到邻接点的权值,则将邻接点的最早发生时间更新为当前顶点事件的最早发生事件加上两点间活动持续时间,
if (early[curVex] + p->weight > early[p->adjVertex])
early[p->adjVertex] = early[curVex] + p->weight;}}
for (int i = 0; i < g->vexNum; i++) 初始化所有事件的最迟开始时间数组last为汇点的最早发生时间,
last[i] = early[g->vexNum - 1];
while (!topOrder.empty()) {
int curVex = topOrder.top();
topOrder.pop();
for (ArcNodePtr p = g->vertexes[curVex].firstArc; p; p = p->nextArc) {
如果邻接点事件的最晚发生时间大于当前顶点事件的最晚发生时间减去当前顶点到邻接点的权值, 则将邻接点的最晚发生时间更新为当前顶点事件的最晚发生时间减去两点间活动持续时间。
if (last[p->adjVertex] - p->weight < last[curVex])
last[curVex] = last[p->adjVertex] - p->weight;}}
算法复杂度:对有n个顶点和e条弧的有向图而言,建立求各顶点的入度的时间复杂度为O(e);建零入度顶点栈的时间复杂度为O(n);在拓扑排序过程中,若有向图无环,则每个顶点进一次栈、出一次栈,入度减1的操作在while语句中总共执行e次,所以总的时间复杂度为O(n+e)。 拓扑排序初始参数只有邻接表,所以第一步建立入度数组,因为每1入度对应一条弧,总共e条弧,建立入度数组的复杂度为O(e)。每个节点输出一次,n个节点遍历一次,时间复杂度为O(n)。然后节点入度减1的操作,也是一条弧对应一次,e条弧总共O(e)。即对每条弧要建立入度数组操作和删除操作,每个顶点要遍历一次并删除。故时间复杂度为O(n+e)。
遍历当前顶点u的所有邻接点
for (ArcNodePtr p = g->vertexes[u].firstArc; p != nullptr; p = p->nextArc) {
如果最早发生时间和最晚发生时间相同的话,说明当前活动是关键活动,则输出当前活动,并从p->adjVertex出发寻找下一个关键活动, 当前顶点事件邻接点的最晚开始时间减去当前活动[u, p -> adjacencyVertex]的权值就是当前活动的最晚开始时间,
if (early[u] == last[p->adjVertex] - p->weight) {
minTime += p->weight;
vec.push_back(u); 将关键活动存入vec中,
vec.push_back(p->adjVertex);
getCriticalPath(g, p->adjVertex, minTime);递归寻找下一个关键活动
找到一条关键路径,结束循环
break;}}
算法时间复杂度为:O(n+e)。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<fstream>
#include<stack>
#include<vector>
using namespace std;
#define MAX_VERTEX_NUM 20
// 链表结点
typedef struct ArcNode {
// 该弧所指向的顶点的位置
int adjVertex;
// 有向边的路径长度(权值)
int weight;
// 下一个和头结点存在有向边的链表结点
struct ArcNode* nextArc;
}ArcNode, * ArcNodePtr;
// 顶点结点
typedef struct VertexNode {
// 存储结点上的数据
char data;
// 指向该顶点结点的第一个链表结点
ArcNodePtr firstArc;
}AdjList[MAX_VERTEX_NUM];
class ALGraph
{
public:
ALGraph() = default;
// early数组记录每个事件的最早发生时间
int early[MAX_VERTEX_NUM] = { 0 };
// last数组记录每个事件的最晚发生时间
int last[MAX_VERTEX_NUM] = { 0 };
// 存储图上所有顶点的数组
AdjList vertexes;
// 图中顶点的数量、边的数量
int vexNum, arcNum;
// 定义minTime表示工程的最短完成时间
int minTime = 0;
vector<int> vec ;
void addEdge(ALGraph* g, int u, int v, int w);
void createALGraph(ALGraph* g);
void getInDegree(ALGraph* g, int* inDegree);
void topOrder(ALGraph* g);
void getCriticalPath(ALGraph* g, int u, int& minTime);
void criticalPath(ALGraph* g);
~ALGraph() = default;
};
// 用头插法在编号为u, v的顶点间增加一条边
void ALGraph::addEdge(ALGraph* g, int u, int v, int w) {
// 创建一个新的链表结点
ArcNodePtr p = new ArcNode();
// 有向边的狐头
p->adjVertex = v;
// 新结点指向头结点后继
p->nextArc = g->vertexes[u].firstArc;
// 有向边<u,v>的权值
p->weight = w;
// 头结点指向新结点
g->vertexes[u].firstArc = p;
}
// 从文件输入中创建邻接表存储的有向图
void ALGraph::createALGraph(ALGraph* g) {
// 文件输入
ifstream input("test01.txt");
// 输入顶点数和边数
input >> g->vexNum >> g->arcNum;
// 输入每个顶点的值并初始化指针为nullptr
for (int i = 0; i < g->vexNum; ++i) {
//让顶点存储的数据为顶点的编号
g->vertexes[i].data = i + '0';
g->vertexes[i].firstArc = nullptr;
}
// 读入<u, v>的一条带权有向边
for (int i = 0; i < g->arcNum; ++i) {
int u, v, w;
input >> u >> v >> w;
addEdge(g, u, v, w);
}
}
// 求图中每个顶点的入度
void ALGraph::getInDegree(ALGraph* g, int* inDegree) {
// 遍历图
for (int i = 0; i < g->vexNum; ++i)
for (ArcNodePtr p = g->vertexes[i].firstArc; p != nullptr; p = p->nextArc)
// 每条有向边的终点顶点入度加一
inDegree[p->adjVertex]++;
}
// 拓扑排序求early和last
void ALGraph::topOrder(ALGraph* g) {
// 每个结点的入度初始化为0
int inDegree[MAX_VERTEX_NUM] = { 0 };
// 求每个顶点的入度数组inDegree
getInDegree(g, inDegree);
// 初始化两个存储int类型下标的栈,st用于存储入度为0的点,topOrder用于存储拓扑排序的顺序
stack<int> st, topOrder;
// 先将所有入度为0的点存入st中
for (int i = 0; i < g->vexNum; ++i)
if (!inDegree[i]) st.push(i);
// 若栈st中存在入度为0的结点,则继续进行拓扑排序
while (!st.empty()) {
// 从栈顶弹出一个图中的顶点,存入topOrder中
int curVex = st.top();
topOrder.push(curVex);
st.pop();
// 遍历该顶点的所有邻接点
for (ArcNodePtr p = g->vertexes[curVex].firstArc; p != nullptr; p = p->nextArc) {
if (!(--inDegree[p->adjVertex]))
// 如果入度减一后该邻接点的入度为0,则加入栈st中作为下一次排序的起点
st.push(p->adjVertex);
if (early[curVex] + p->weight > early[p->adjVertex])
early[p->adjVertex] = early[curVex] + p->weight;
}
}
//初始化所有事件的最迟开始时间数组last为汇点的最早发生时间
for (int i = 0; i < g->vexNum; i++)
last[i] = early[g->vexNum - 1];
while (!topOrder.empty()) {
// 获取栈顶元素
int curVex = topOrder.top();
topOrder.pop();
// 遍历当前顶点的所有邻接点
for (ArcNodePtr p = g->vertexes[curVex].firstArc; p; p = p->nextArc) {
if (last[p->adjVertex] - p->weight < last[curVex])
last[curVex] = last[p->adjVertex] - p->weight;
}
}
// 输出所有顶点的early值
cout << "early: ";
for (int i = 0; i < g->vexNum; ++i)
cout << early[i] << " ";
// 输出所有顶点的last值
cout << endl << "last: ";
for (int i = 0; i < g->vexNum; ++i)
cout << last[i] << " ";
}
// 求解关键路径
void ALGraph::getCriticalPath(ALGraph* g, int u, int& minTime) {
// 遍历当前顶点u的所有邻接点
for (ArcNodePtr p = g->vertexes[u].firstArc; p != nullptr; p = p->nextArc) {
if (early[u] == last[p->adjVertex] - p->weight) {
minTime += p->weight;
// 将关键活动存入vec中
vec.push_back(u);
vec.push_back(p->adjVertex);
getCriticalPath(g, p->adjVertex, minTime);
// 找到一条关键路径,结束循环
break;
}
}
}
void ALGraph::criticalPath(ALGraph* g) {
cout << endl << "关键路径:";
getCriticalPath(g, 0, minTime);
for (int i = 0; i < vec.size(); i = i + 2) {
cout << "V" <<vec[i] <<"->";
}
cout << "V" << vec[vec.size() - 1];
cout << endl << "工程最短完成时间: " << minTime;
}
int main() {
ALGraph* G = new ALGraph();
G->createALGraph(G); // 创建图的图的邻接表存储
G->topOrder(G); //拓扑排序
G->criticalPath(G); //求关键路径
G->~ALGraph();
return 0;
}
test01.txt文件输入为:
7 8
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 7
5 6 4
屏幕输出:
文章浏览阅读1.5w次,点赞10次,收藏129次。文章目录目录模型评估评价指标1.分类评价指标acc、recall、F1、混淆矩阵、分类综合报告1.准确率方式一:accuracy_score方式二:metrics2.召回率3.F1分数4.混淆矩阵5.分类报告6.kappa scoreROC1.ROC计算2.ROC曲线3.具体实例2.回归评价指标3.聚类评价指标1.Adjusted Rand index 调整兰德系数2.Mutual Informa..._model.score
文章浏览阅读344次。因工作需要,在Apache上使用,重新学习配置mod_jk1. 分别安装Apache和Tomcat:2. 编辑httpd-vhosts.conf: LoadModule jk_module modules/mod_jk.so #加载mod_jk模块 JkWorkersFile conf/workers.properties #添加worker信息 JkLogFil_apache mod_jk 虚拟
文章浏览阅读335次。待老夫kotlin大成,扩展:MotionLayout 与 CoordinatorLayout,DrawerLayout,ViewPager 的 交互众所周知,MotionLayout 的 动画是有完成度的 即Progress ,他在0-1之间变化,一.CoordinatorLayout 与AppBarLayout 交互时,其实就是监听 offsetliner 这个 偏移量的变化 同样..._android onoffsetchanged
文章浏览阅读8.3k次,点赞3次,收藏19次。【转】多核处理器的工作原理及优缺点《处理器关于多核概念与区别 多核处理器工作原理及优缺点》原文传送门 摘要:目前关于处理器的单核、双核和多核已经得到了普遍的运用,今天我们主要说说关于多核处理器的一些相关概念,它的工作与那里以及优缺点而展开的分析。1、多核处理器 多核处理器是指在一枚处理器中集成两个或多个完整的计算引擎(内核),此时处理器能支持系统总线上的多个处理器,由总..._多核处理器怎么工作
文章浏览阅读306次。1. eclipse配置lombok 拷贝lombok.jar到eclipse.ini同级文件夹下,编辑eclipse.ini文件,添加: -javaagent:lombok.jar2. myeclipse配置lombok myeclipse像eclipse配置后,定义对象后,直接访问方法,可能会出现飘红的报错。 如果出现报错,可按照以下方式解决。 ..._eclispe每次运行个新项目都需要重新配置lombok吗
文章浏览阅读1.2w次,点赞31次,收藏126次。#注意:笔者在2021/11/11当天调试过这个代码是可用的,由于pdfminer版本的更新,网络上大多数的语法没有更新,我也是找了好久的文章才修正了我的代码,仅供学习参考。1、把pdf文件移动到本代码文件的同一个目录下,笔者是在pycharm里面运行的项目,下图中的x1文件夹存储了我需要转换成文本文件的所有pdf文件。然后要在此目录下创建一个存放转换后的txt文件的文件夹,如图中的txt文件夹。2、编写代码 (1)导入所需库# coding:utf-8import ..._python批量读取文字并批量保存
文章浏览阅读1.4k次。http://blog.csdn.net/pipisorry/article/details/52902234Scala 访问修饰符Scala 访问修饰符基本和Java的一样,分别有:private,protected,public。如果没有指定访问修饰符符,默认情况下,Scala对象的访问级别都是 public。Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层_scala ===运算符
文章浏览阅读2.6k次,点赞7次,收藏19次。ER图导出为PDF或图片格式_数据库怎么导出er图
文章浏览阅读655次。CREATE OR REPLACE TRIGGER Trg_ReimFactBEFORE UPDATEON BP_OrderFOR EACH ROWDECLAREPRAGMA AUTONOMOUS_TRANSACTION;--自制事务fc varchar2(255);BEGINIF ( :NEW.orderstate = 2AND :NEW.TransState = 1 ) THENBEG..._oracle触发器更新同一张表
文章浏览阅读513次。目录概念debouncethrottle实现debouncethrottle应用场景debouncethrottle场景举例debouncethrottle概念debounce字面理解是“防抖”,何谓“防抖”,就是连续操作结束后再执行,以网页滚动为例,debounce要等到用户停止滚动后才执行,将连续多次执行合并为一次执行。throttle字面理解是“节流”,何谓“节流”,就是确保一段时..._throttle和debounce应用在哪些场景
文章浏览阅读526次。regex() $regex 正则表达式用于模式匹配,基本上是用于文档中的发现字符串 (下面有例子)注意:若未加 @Field("名称") ,则识别mongdb集合中的key名为实体类属性名。也可以对数组进行索引,如果被索引的列是数组时,MongoDB会索引这个数组中的每一个元素。也可以对整个Document进行索引,排序是预定义的按插入BSON数据的先后升序排列。save: 若新增数据的主键已经存在,则会对当前已经存在的数据进行修改操作。_java 操作mongodb
文章浏览阅读1k次。今天push代码到github仓库时出现这个报错TACKCHEN-MB0:tc-image tackchen$ git pushremote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.remote: Please see https://github.blog/2020-12-15-token-authentication_git push remote: support for password authentication was removed on august 1