算法-图(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]=0Ve[n-1]=Vl[n-1]

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

在拓扑排序求Ve[i]和逆拓扑排序求Vl[i]时,所需时间为O(n+e),求各个活动的Ve[i]和Vl[j]-活动(ij)完成时间所需时间为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;
}
原文地址:https://www.cnblogs.com/yangyuliufeng/p/9294965.html