# AOV: Activity On Vertex
略(不考)
# AOE: Activity On Edge
与 AOV 网相对应的是 AOE (Activity On Edge) ,是边表示活动的有向无环图,如图所示。图中顶点表示事件 (Event),每个事件表示在其前的所有活动已经完成,其后的活动可以开始;弧表示活动,弧上的权值表示相应活动所需的时间或费用
与 AOE 有关的研究问题
- 完成整个工程至少需要多少时间?
- 哪些活动是影响工程进度 (费用) 的关键?
工程完成最短时间:从起点到终点的最长路径长度 (路径上各活动持续时间之和)
长度最长的路径称为关键路径,关键路径上的活动称为关键活动。 关键活动是影响整个工程的关键。
# 求 AOE 中关键路径和关键活动
设 是起点,从 到 的最长路径长度称为事件 的最早发生时间,即是 以 为尾的所有活动的最早发生时间。
若活动 是弧,持续时间是, 设:
: 表示活动 的最早开始时间;
: 在不影响进度的前提下,表示活动 的最晚开始时间;
表示活动 的时间余量,若,表示活动 是关键活动
: 表示事件 的最早发生时间,即从起点到顶点 的最长路径长度
: 表示事件 的最晚发生时间
则有以下关系:
并且:
含义是:源点事件的最早发生时间设为 0; 除源点外,只有进入顶点 的所有弧所代表的活 动全部结束后,事件 才能发生。即只有 的所有前驱事件 的最早发生时间 计算出来 后,才能计算。
方法是:对所有事件进行拓扑排序,然后依次按拓扑顺序计算每个事件的最早发生时间。
含义是:只有 的所有后继事件 的最晚发生时间 计算出来后,才能计算 。
方法是:按拓扑排序的逆顺序,依次计算每个事件的最晚发生时间。
# 算法思想
利用拓扑排序求出 AOE 网的一个拓扑序列;
从拓扑排序的序列的第一个顶点 (源点) 开始,按拓扑顺序依次计算每个事件的最早发生时间;
从拓扑排序的序列的最后一个顶点 (汇点) 开始,按逆拓扑顺序依次计算每个事件的最晚发生时间;
# 代码实现
void critical_path(ALGraph *G) //Adjacency List Graph | |
{ | |
int j, k, m ; LinkNode *p ; | |
if (Topologic_Sort(G)==-1) | |
printf("\nAOE网中存在回路,错误!!\n\n"); | |
else | |
{ | |
for (j=0; j<G->vexnum; j++) | |
ve[j]=0; // 事件最早发生时间初始化 | |
for (m=0 ; m<G->vexnum; m++) | |
{ | |
j=topol[m] ; | |
p=G->adjlist[i].firstarc ; | |
for(; pl=NULL; p=p->nextarc ) | |
{ | |
k=p->adjvex; | |
if (ve[j]+p->weight>ve[k]) | |
ve[k]=ve[j]+p->weight ; | |
} | |
}// 计算每个事件的最早发生时间 ve 值 | |
for ( j=0; j<G->vexnum; j++) | |
vl[j]=ve[j];// 事件最晚发生时间初始化 | |
for (m=G->vexnum-1; m>=0, m--) | |
{ | |
j=topol[m] ; | |
p=G->adjlist[i].firstarc; | |
for (; pl=NULL; p=p->nextarc) | |
{ | |
k=p->adjvex ; | |
if (vl[k]-p->weight<vl[j]) | |
vl[i]=$v_i$[k]-p->weight ; | |
} | |
}// 计算每个事件的最晚发生时间 vl 值 | |
for (m=0 , m<G->vexnum; m++) | |
{ | |
p=G->adjlist[m].firstarc ; | |
for(; p!=NULL; p=p->nextarc ) | |
{ | |
k=p->adjvex; | |
if ( (ve[m]+p->weight)==l[k]) | |
printf("<%d, %d>, m, j"); | |
} | |
}// 输出所有的关键活动 | |
}//end of else | |
} |
# 算法分析
设 AOE 网有 n 个事件,e 个活动,则算法的主要执行是:
进行拓扑排序:时间复杂度是
求每个事件的 ve 值和 vl 值:时间复杂度是
根据 ve 值和 vl 值找关键活动:时间复杂度是
因此,整个算法的时间复杂度是