1、在AOE-网中,顶点表示事件,边表示活动
2、存储形式:邻接表
3、实现关键:寻找e[i] = l[i]的活动i
为了达到此目的,我们先求ve、vl(顶点的最早、最晚开始时间)
①求ve:初始化ve数组为0,因为最早开始时间越晚越好,所以初始值设的很小,如果某条边首的最早开始时间小于尾的最早开始时间+权重,那么就更新首的最早开始时间(按照拓扑排序顺序来)
②求vl:初始化vl数组为汇点的最早开始时间,因为最晚开始时间越早越好,所以初始值设的很大,如果某条边尾的最晚开始时间大于尾的最晚开始时间-权重,那么就更新尾的最晚开始时间(按照逆拓扑排序顺序来)
然后遍历顶点结点,根据弧的信息找到是那个活动,然后求该活动的e、l(最早、最晚开始时间),活动的最早开始时间等于弧尾的最早开始时间,活动的最晚开始时间等于弧头的最晚开始时间减去权重(活动持续时间)
e、l相等的活动就是关键活动
测试数据及结果
AOE-网:
输入网的信息:
运行结果:
实现代码:
/*
实现内容:
关键路径的求法
VS2019 编译通过
2020.8.8 王大花
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VexDateType char
#define StackElemType int
#define MaxVexDateLength 3
#define MaxActNameLength 2
#define MaxStackLength 100
#define TextPath "C:\\Users\\86132\\Desktop\\第7章 作业\\关键路径\\ALGraph.txt"
//邻接表表示法
//弧结点
typedef struct _ARCINFO {
int Weight;
char AcName[MaxActNameLength + 1];
}ArcInfo;
typedef struct _ARCNODE ArcNode;
struct _ARCNODE {
int AdjVex;
ArcNode* Next;
ArcInfo Info;
};
//顶点结点
typedef struct _VEXNODE {
VexDateType Date[MaxVexDateLength + 1];
ArcNode* FirstArc;
}VexNode;
//图
typedef struct _ALGRAPH {
VexNode* Vertics;
int VexNum;
int ArcNum;
int* InDegree;
}ALGraph;
//栈辅助拓扑排序(pos便于后续输出课程)
typedef struct _STACK {
StackElemType* Vertics;
int tail, pos;
}Stack;
void InitStack(Stack* S) {
S->Vertics = (StackElemType*)malloc(MaxStackLength * sizeof(StackElemType));
S->pos = S->tail = 0;
}
void Push(Stack* S, int n) {
S->Vertics[S->tail++] = n;
}
int Pop(Stack* S) {
return S->Vertics[--S->tail];
}
int Get_Top(Stack S) {
return S.Vertics[S.tail - 1];
}
//根据元素寻找顶点位置 默认元素为V1 V2 V3 ……顺序排布
int Locate(char* ch) {
return (3 == strlen(ch)) ? 10 * (ch[1] - '0') + ch[2] - '1' : ch[1] - '1';
}
//从文件读取信息
void Creat_ALGraph(ALGraph* G) {
FILE* fp = fopen(TextPath, "r");
//读取顶点数量 弧的数量
fscanf(fp, "%d%d", &G->VexNum, &G->ArcNum);
G->Vertics = (VexNode*)malloc(sizeof(VexNode) * G->VexNum);
for (int i = 0; i < G->VexNum; i++)
G->Vertics[i].FirstArc = NULL;
//读取顶点信息
for (int i = 0; i < G->VexNum; i++)
fscanf(fp, "%s", G->Vertics[i].Date);
//读取弧的信息
for (int i = 0; i < G->ArcNum; i++) {
char str1[3], str2[3];
int pos1, pos2;
fscanf(fp, "%s%s", str1, str2);
pos1 = Locate(str1);
pos2 = Locate(str2);
ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
p->AdjVex = pos2;
p->Next = G->Vertics[pos1].FirstArc;
fscanf(fp, "%s%d", p->Info.AcName, &p->Info.Weight);
G->Vertics[pos1].FirstArc = p;
}
fclose(fp);
//更新入度数组
G->InDegree = (int*)malloc(sizeof(int) * G->VexNum);
memset(G->InDegree, 0, sizeof(int) * G->VexNum);
for (int i = 0; i < G->VexNum; i++) {
for (ArcNode* p = G->Vertics[i].FirstArc; NULL != p; p = p->Next) {
G->InDegree[p->AdjVex]++;
}
}
}
//e是事件的最早时间
Stack TopologicalSort(ALGraph G, int* ve) {
Stack S, OutCome;
InitStack(&S);
InitStack(&OutCome);
memset(ve, 0, sizeof(int) * G.VexNum);
//寻找入度为0的顶点入栈
for (int i = 0; i < G.VexNum; i++) {
if (!G.InDegree[i]) {
Push(&S, i);
}
}
while (0 < S.tail) {
int tmp = Pop(&S);
Push(&OutCome, tmp);
//重新更新入度
for (ArcNode* p = G.Vertics[tmp].FirstArc; NULL != p; p = p->Next) {
G.InDegree[p->AdjVex]--;
if (0 == G.InDegree[p->AdjVex])
Push(&S, p->AdjVex);
//更新事件的最早时间数组
if (ve[tmp] + p->Info.Weight > ve[p->AdjVex])
ve[p->AdjVex] = ve[tmp] + p->Info.Weight;
}
}
if (OutCome.tail < G.VexNum)
exit(EXIT_FAILURE);
return OutCome;
}
//关键路径 ve是事件的最早发生时间
void CriticialPath(ALGraph G, int* ve, Stack S) {
//初始化事件最晚发生数组
int* vl = (int*)malloc(sizeof(int) * G.VexNum);
for (int i = 0; i < G.VexNum; i++)
vl[i] = ve[Get_Top(S)];
while (0 != S.tail) {
int tmp = Pop(&S);
for (ArcNode* p = G.Vertics[tmp].FirstArc; NULL != p; p = p->Next) {
if (vl[tmp] > vl[p->AdjVex] - p->Info.Weight)
vl[tmp] = vl[p->AdjVex] - p->Info.Weight;
}
}
//活动的最早、最晚开始时间
int* e = (int*)malloc(sizeof(int) * G.ArcNum), * l = (int*)malloc(sizeof(int) * G.ArcNum);
for (int i = 0; i < G.VexNum; i++) {
for (ArcNode* p = G.Vertics[i].FirstArc; NULL != p; p = p->Next) {
//更新活动最早发生时间
e[Locate(p->Info.AcName)] = ve[i];
//更新活动最晚发生时间
l[Locate(p->Info.AcName)] = vl[p->AdjVex] - p->Info.Weight;
}
}
printf("关键活动为:");
for (int i = 0; i < G.ArcNum; i++) {
if (e[i] == l[i])
printf("a%d ", i + 1);
}
printf("\n");
free(e);
free(l);
free(vl);
free(ve);
}
int main(void) {
ALGraph G;
Stack S;
InitStack(&S);
Creat_ALGraph(&G);
int* ve = (int*)malloc(sizeof(int) * G.VexNum);
S = TopologicalSort(G, ve);
CriticialPath(G, ve, S);
return 0;
}