关键路径
A.相关概念
-
AOE网:边表示活动,顶点表示事件,边上权值表示活动持续时间。
-
AOV网:顶点表示活动,弧表示活动间的优先关系。
-
关键路径用AOE网,顶点表示活动,弧表示活动间的优先关系。
-
入度:到达此顶点的路径条数。
-
出度:从此顶点出去的路径条数。
-
源点:入度为0,路径起始点。
-
汇点:出度为0,路径终止点。
-
拓扑序列:
vi~vj
间有一条路径,则这条路径就是拓扑序列。 -
拓扑排序:对有向图构造拓扑序列的过程。
-
对AOV网拓扑排序的思路:
1.找到入度为0的顶点输出;
2.删去此顶点,及以改顶点为尾的弧;
3.重复1,2两步,直到没有入度为0的顶点。
-
路径长度:路径上各个活动所持续的时间之和。
-
关键路径:从源点到汇点具有最大长度的路径。
-
关键活动:关键路径上的活动。
[link]:(62条消息) 图解:什么是关键路径?_ZenjaminFranklin的博客-CSDN博客
B.编码步骤
-
1.建立连接表。
-
2.用拓扑排序得最早发生时间
etv[]
a.初始化入度为0的栈stack(定义+开空间)。
b.遍历顶点,将入度为0的顶点入栈。
c.初始化
etv[]
(开空间+初始值为0)。d.初始化拓扑序列栈stack2(后序用于求最晚发生时间
ltv[]
)。e.遍历stack中的顶点,确定
etv[]
的值。etv[0]=0
etv[k]=max{etv[i]+len<vi,vk>}
-
3.根据事件的最早发生时间
etv[]
算事件的最迟发生时间ltv[]
a.初始化
ltv[]
,与etv[n-1]
值相同。b.遍历stack2,求
ltv
的值。ltv[n-1]=etv[k]
ltv[k]=min{ltv[j]-len<vk,vj>}
-
4.求关键活动
a.遍历每个点。
b.确定活动最早发生时间
ete
,和活动最迟发生时间lte
。c.如果
ete==lte
则在关键路径上。
#include<stdio.h> #include<stdlib.h> #define MAXVEX 99 //储存结构 //边表结点 typedef struct EdgeNode { int adjvex;//邻接点域:储存与之相连的顶点下标 int weight;//储存权值 struct EdgeNode* next;//链域:指向上一个邻接点 }EdgeNode; //顶点表结点 typedef struct VertexNode { int in;//顶点入度 int data;//顶点域,储存顶点信息 EdgeNode* firstedge;//边表头指针 }vertexNode,AdjList[MAXVEX]; //图表 typedef struct { AdjList adjList; int numVertexes, numEdges;//图中当前顶点数和边数 }*graphAdjList,GraphAdjList; //创建邻接表 void CreateALGraph(GraphAdjList* G) { int i, j, k,w; EdgeNode* e; printf("输入顶点数和边数:\n"); scanf("%d%d", &G->numVertexes, &G->numEdges); //建立顶点表 printf("请输入顶点数据:\n"); for (i = 0; i < G->numVertexes; i++) { scanf("%d", &G->adjList[i].data); G->adjList[i].firstedge = NULL;//边表置空 G->adjList[i].in = 0; } //建立边表 printf("输入i,j,w:\n"); for (k = 0; k < G->numEdges; k++) { scanf("%d%d%d", &i, &j, &w); //存i顶点 e = (EdgeNode*)malloc(sizeof(EdgeNode));//申请内存空间,生成边表结点 e->adjvex = j;//邻接结点序号j e->next = G->adjList[i].firstedge;//e的指针指向当前顶点指向的结点 e->weight = w; G->adjList[i].firstedge = e;//保存当前顶点的头指针 //存j顶点 e = (EdgeNode*)malloc(sizeof(EdgeNode)); G->adjList[j].in=G->adjList[j].in+1; e->adjvex = i; //e->weight = w; e->next = G->adjList[j].firstedge; G->adjList[j].firstedge = e; } } //输出邻接表 void OutPutLink(GraphAdjList* GL) { int i; EdgeNode* p; printf("图的邻接表表示如下:\n"); printf("%6s%8s%12s\n", "编号", "顶点", "相邻边编号"); for (i = 0; i < GL->numVertexes; i++) { printf("%4d %8d", i, GL->adjList[i].data); for (p = GL->adjList[i].firstedge; p != NULL; p = p->next)printf("%4d", p->adjvex); printf("\n"); } } //关键路径 int* etv;//事件最早发生时间 int *ltv;//事件最迟发生时间 int *stack2;//储存拓扑序列的栈,用于计算ltv int top2;//stack2栈顶指针 //拓扑排序 #define OK 1 #define ERROR 0 typedef int Status; //若GL无回路,则输出拓扑序列并返回1 Status TopologicalSort(graphAdjList GL) { EdgeNode* e; int i, k; int gettop;//临时储存栈顶元素 int* stack;//储存入度为0顶点的栈 int top = 0;//stack栈顶指针 int count = 0;//统计输出顶点的个数 //初始化stack stack = (int*)malloc(GL->numVertexes * sizeof(int)); //入度为0的顶点入栈 for (i = 0; i < GL->numVertexes; i++) { if (GL->adjList[i].in == 0) { stack[++top] = i; } } //初始化etv etv = (int*)malloc(GL->numVertexes * sizeof(int)); //事件最早发生数组初始化为0 for (i = 0; i < GL->numVertexes; i++) { etv[i] = 0; } //初始化序列栈stack2 stack2 = (int*)malloc(GL->numVertexes * sizeof(int)); top2 = 0; //清空入度为0的栈 while (top != 0) { gettop = stack[top--];//临时保存栈顶元素 count++;//计数出栈的顶点 stack2[++top2] = gettop;//将弹出的顶点压入拓扑序列栈 for (e = GL->adjList[gettop].firstedge; e; e = e->next)//遍历与gettop顶点相关联的邻接顶点 { k = e->adjvex;//临时储存邻接顶点域 //判断是否有需要入栈的新结点 if (!(--GL->adjList[k].in))//删除顶点gettop后,判断是否出现新的入度为0的点,有则入栈 { stack[++top] = k; } //更新最早发生时间etv的值 if ((etv[gettop] + e->weight) > etv[k]) { etv[k] = etv[gettop] + e->weight; } } } if (count < GL->numVertexes) { return ERROR; } else { return OK; } } //求关键路径,输出G的各项关键活动 void CriticalPath(graphAdjList GL) { EdgeNode* e; int i, j, k, gettop; int ete;//活动最早发生时间 int lte;//活动最迟发生时间 TopologicalSort(GL);//计算拓扑序列,得etv和stack2的值 //初始化ltv ltv = (int*)malloc(GL->numVertexes * sizeof(int)); for (i = 0; i < GL->numVertexes; i++) { ltv[i] = etv[GL->numVertexes - 1]; } //计算ltv while (top2 != 0) { gettop = stack2[top2--]; for (e = GL->adjList[gettop].firstedge; e; e = e->next)//遍历gettop的邻接顶点 { k = e->adjvex; if (ltv[k] - e->weight < ltv[gettop])//求各邻接顶点最晚发生时间 { k = e->adjvex; if (ltv[k] - e->weight < ltv[gettop]) { ltv[gettop] = ltv[k] - e->weight; } } } } //求ete,lte和关键路径 for (j = 0; j < GL->numVertexes; j++) { for (e = GL->adjList[j].firstedge; e; e = e->next) { k = e->adjvex; ete = etv[j];//活动最早发生时间 lte = ltv[k] - e->weight;//活动最迟发生时间 if (ete == lte) { printf("<v%d - v%d> length: %d\n", GL->adjList[j].data, GL->adjList[k].data, e->weight); } } } } int main() { GraphAdjList* GL; if (!(GL = (GraphAdjList*)malloc(sizeof(GraphAdjList))))return 0; CreateALGraph(GL); OutPutLink(GL); CriticalPath(GL); return 0; }