C语言实现 寻找AOE-网的关键路径

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值