1. 相关概念:
1. 有向无环网(Activity On Edge Network,简写为AOE)
- 用顶点表示事件, 弧表示活动, 边上权值表示活动的消耗时间
- AOE与AOV网的比较: AOV网的边+权值=AOE网
2. 始点, 源点:
AOE网中,没有入边的顶点
3. 终点, 汇点:
AOE网中, 没有出边的顶点
4. AOE网中事件发生的条件:
入度活动都得执行完, 该事件具备发生的条件
5. 事件最早发生时间:
即刚好全部前提活动都执行完的时间, 取决于最长的前提路径
6. 事件最晚发生时间:
如果该事件晚于该事件, 则会延误整个工期, 取决于==到终点的最短路径==
7. 活动的最早发生时间:
由弧尾最早发生时间决定
8. 活动最晚发生时间:
- 该活动不能更晚发生的时间点, 否则将延误整个工期
- 由弧头顶点的最晚时间和该活动所花费时间决定
9. 关键弧
最早和最晚时间相同的弧, 即该活动必须立刻执行, 否则将会延误整个工期
2. 算法思想:
- 求出所有关键弧, 以此拼凑出关键路径
- 关键弧判定条件: 最早发生时间=最晚发生时间
- 分别根据弧头和弧尾求出两个时间
- 关键弧判定条件: 最早发生时间=最晚发生时间
3. 在C语言中的实现
梗概:
- 用拓扑顺序来求每个顶点的最早发生时间
- 并由此得到反拓扑序列
- 用反拓扑顺序来求每个顶点的最晚发生时间
- 遍历每条弧, 找出所有关键弧
- 根据顶点两个时间求出弧的两个对应时间
- 弧的两个时间相等, 则该弧为关键弧 代码:
int vEinTopoOrder(AdjList *G,int* T,int *vE){
//有环返回0,无环返回1
/*存储*/
ArcNode *e;
int i, k, gettop;
int top=0;
int count=0;
int *stack,*indegree;
indegree=(int*)calloc(G->vexnum,sizeof(int));
stack=(int*)calloc(G->vexnum,sizeof(int));
vE=(int*)calloc(G->vexnum,sizeof(int));
T=(int*)calloc(G->vexnum,sizeof(int));
int top_T=0;
/*统计所有顶点的入度*/
for(i=0;i<G->vexnum;++i)
indegree[i]=0;
for(i=0;i<G->vexnum;++i){
e=G->vertex[i].firstarc;
for(;e;){
++indegree[e->adjvex];
e=e->nextarc;
}
}
for(i=0;i<G->vexnum;++i)
vE[i]=0;
/*把所有入度为0的顶点都入栈*/
for(i=0;i<G->vexnum;++i)
if(!(indegree[i]))
stack[++top]=i;
for(;top;){
/*获得拓扑顺序*/
gettop=stack[top--];
/*获取反拓扑序列*/
T[++top_T]=gettop;
count++;
/*遍历出度顶点*/
for(e=G->vertex[gettop].firstarc;e;){
k=e->adjvex;
/*删除入度,并判断删除后入度是否可以进栈*/
if(!(--indegree[k]))
stack[++top]=k;
/*取最长的路径作顶点最早时间*/
if(vE[gettop]+e->info > vE[k])
vE[k]=vE[gettop]+e->info;
e=e->nextarc;
}
}
free(indegree);
free(stack);
/*如果有环,就会有顶点没有排序到*/
return!(count<G->vexnum);
}
int CriticalPath(AdjList *G){
ArcNode *e;
int i,tail,head,costT,edgeE,edgeL,top; char tag;
int *vL=(int*)calloc(G->arcnum,sizeof(int));
int *T,*vE;
/*获取所有顶点最早发生时间vE,并获取反拓扑序列*/
if(!vEinTopoOrder(G,T,vE))return 0;
/*初始化顶点时间与最早时间相等*/
for(i=0;i<G->vexnum;++i)
vL[i]=vE[G->vexnum-1];
/*遍历反拓扑序列来求vL*/
for(;top;){
tail=T[top--];
e=G->vertex->firstarc;
/*遍历所有出度弧*/
for(;e;){
head=e->adjvex;costT=e->info;
/*取最短反路径为顶点最晚时间*/
if(vL[head]-costT < vL[tail])
vL[tail]=vL[head]-costT;
e=e->nextarc;
}
}
/*遍历所有弧,以找出所有关键弧*/
for(tail=0;tail < G->vexnum;++tail){
e=G->vertex[tail].firstarc;
for(;e;){
head=e->adjvex; costT=e->info;
/*根据顶点最晚和最早时间求弧的对应时间*/
edgeE=vE[tail]; edgeL=vL[head]-costT;
/*两个时间相等说明该弧为关键路径之一*/
tag=(edgeE==edgeL)?'*':' ';
/*打印关键路径中的一部分*/
printf("%c,%c,%d,%d,%d,%c\n",G->vertex[tail].data,
G->vertex[head].data,costT,edgeE,edgeL,tag);
e=e->nextarc;
}
}
free(vL);
free(T);
free(vE);
return 1;
}