算法-图(4)用边表示活动的网络(AOE网络)Activity On Edge Network

时间:2024-04-14 12:21:38

有向边表示活动,权值表示活动的持续时间,顶点表示事件。

只有一个开始点和完成点,称为源点、汇点,完成工程时间取决于从源点到汇点的最长路径长度,即在这条路径(关键路径)上所有活动的持续时间之和。关键路径上的活动都是关键活动,不按期完成就会影响整个工程的完成时间。

事件最早可能开始时间Ve[n],是从源点到顶点i的最长长度,需要正向计算取大得出。

事件最迟允许开始时间Vl[n],Vl[i]=Ve[n-1]-(i到n-1的最长路径长度)。超过该时间会影响汇点事件在Ve[n-1]完成,需要逆向计算取小得到。

源点和汇点有Ve[0]=Vl[0]=0,Ve[n-1]=Vl[n-1]

关键路径上的活动有Ve[i]=Vl[j]-活动(i,j)完成时间,用此判断关键活动。

在拓扑排序求Ve[i]和逆拓扑排序求Vl[i]时,所需时间为O(n+e),求各个活动的Ve[i]和Vl[j]-活动(i,j)完成时间所需时间为O(e),总花费时间仍为O(n+e)。

//  程序为了简化算法,假定在求关键路径之前已经对各顶点实现了拓扑排序,并按拓扑有序的顺序对各顶点重新进行了编号

template <class T,class E>
void CriticalPath(Graph<T,E>& G){
int i,j,k;
E Ae,Al,w;
int n=G.NumberOfVerticles();
E *Ve=new E[n]; //最早可能开始时间
E *Vl=new E[n]; //最迟必须开始时间
for (i=; i<n; i++) Ve[i]=;
for(i=; i<n; i++){ //正向计算Ve[]
j=G.getFirstNeighbor(i);
while(j!=-){
w=G.getWeight(i,j);
if(Ve[i]+w>Ve[j]) Ve[j]=Ve[i]+w;
j=G.getNextNeighbor(i,j);
}
}
Vl[n-]=Ve[n-];
for(j=n-; j>; j--){ //逆向计算Vl[]
k=G.getFirstNeighbor(j);
while(k!=-){
w=G.getWeight(j,k);
if(Vl[k]-w<Vl[j]) Vl[j]=Vl[k]-w;
k=G.getNextNeighbor(j,k);
}
}
for(i=; i<n; i++){
j=G.getFirstNeighbor(i);
while(j!=-){
Ae=Ve[i];
Al=Vl[j]-G.getweight(i,j);
if(Al==Ae) cout<<"<"<<G.getValue(i)<<","<<G.getValue(j)<<">"<<"是关键活动"<<endl; //活动是没有时间余量的关键活动,i必须在最早开始时间完成,否则会影响j在最迟开始时间完成
j=G.getNextNeighbor(i,j);
}
}
delete []Ve;
delete []Vl;
}