算法-图(4)用边表示活动的网络(AOE网络)Activity On Edge Network
有向边表示活动,权值表示活动的持续时间,顶点表示事件。
只有一个开始点和完成点,称为源点、汇点,完成工程时间取决于从源点到汇点的最长路径长度,即在这条路径(关键路径)上所有活动的持续时间之和。关键路径上的活动都是关键活动,不按期完成就会影响整个工程的完成时间。
事件最早可能开始时间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=0; i<n; i++) Ve[i]=0; for(i=0; i<n; i++){ //正向计算Ve[] j=G.getFirstNeighbor(i); while(j!=-1){ w=G.getWeight(i,j); if(Ve[i]+w>Ve[j]) Ve[j]=Ve[i]+w; j=G.getNextNeighbor(i,j); } } Vl[n-1]=Ve[n-1]; for(j=n-2; j>0; j--){ //逆向计算Vl[] k=G.getFirstNeighbor(j); while(k!=-1){ w=G.getWeight(j,k); if(Vl[k]-w<Vl[j]) Vl[j]=Vl[k]-w; k=G.getNextNeighbor(j,k); } } for(i=0; i<n; i++){ j=G.getFirstNeighbor(i); while(j!=-1){ 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; }