拓扑排序和关键路径

《拓扑排序和关键路径》

 

拓扑排序:

       每次选择前驱节点为0的节点,然后删除以其为顶点的边,重复上述操作,直到删除所有节点为止或者所有节点都有前驱.若还有剩余节点,那么图存在环.

关键路径(图中最长的路径):

活动:图中的弧.

事件:图中的顶点.

由于活动时间长短可能不同,导致事件发生的时间可以不同,v1vi的最长路径长度是节点i最早发生时间,不推迟整个工程完成的情况下,事件vi最迟开始时间.

1.根据拓扑序,更新所有节点的最早发生时间,使其最大.

2.令终点的最迟开始时间等于最早发生时间.

3.根据逆拓扑序,更新所有节点的最迟开始时间,使其最小.

4.如果一个节点的最迟开始时间等于最早发生时间,那么该事件为关键事件,如果一条弧两端的节点都是关键事件,那么该弧为关键活动.这样就可以查找到所有关键活动了.

 

(1)为什么要根据拓扑序来扩展节点?

       因为当拓扑序扩展到某一个节点时候,该节点已经没有前驱了.所以可以到达该节点的路径都已经计算过了,即该节点所记录的路径值为v0到达vi的最大值.

(2)为什么要根据逆拓扑序来计算最迟开始时间?

       如果一个图可以进行拓扑排序,那么把该图中所有路径首尾倒置,即箭头方向调转,该图也一定可以进行拓扑排序,且和倒转前的图的拓扑排序恰好相反.这样,我们可以把逆拓扑序看作路径倒转后的拓扑序.这样根据上面的拓扑序扩展原理,此处我们使用逆拓扑序可以令扩展出来的节点的最迟开始时间最小

 

#include<iostream>
#include<deque>
#include<stack>
#include<queue>
 
usingnamespace std;
#defineVexNum 9
#defineVEXMAX 100000
typedefchar VextexType;
typedefint  EdgeType;
 
 
structEdgeNode;
structEdgeNode {
    VextexType HeadName;
    VextexType TailName;
    EdgeType  weight;
    EdgeNode  *VexOut;
    EdgeNode  *VexIn;
  
};
 
structvexTopological {
    char name;
    int preVexNum;
    int early;
    int last;
    bool isUsed;
}vextopo[VexNum];
 
structvexWeight{
    char name;
    int pathWeight;
    char path[VexNum+1];
};
 
typedefstruct
{
    VextexType name;
    EdgeNode  *VexOutlink;
    EdgeNode  *VexInlink;
}VexNode;
 
VexNodeadjList[VexNum];
 
 
 
 
voidcreatGraph()
{
 
    VextexType vextemp;
    EdgeType  edgetemp;
    //char a[]={'A','B','C','D','E'};
    char a[]={'A', 'B', 'C', 'D', 'E', 'F','G', 'H', 'I'};
    int b[] = {
        0, 6, 4, 5, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 2, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 9, 7, 0,
        0, 0, 0, 0, 0, 0, 0, 4, 0,
        0, 0, 0, 0, 0 ,0 ,0, 0, 2,
        0, 0, 0, 0 ,0 ,0, 0, 0, 4,
        0, 0, 0, 0, 0, 0, 0, 0, 0};
    //input n vextex
    for ( int i=0; i<VexNum ; ++i ){
        cin>>vextemp;
        //vextemp = a[i];
        adjList[i].name       = vextemp;
        adjList[i].VexOutlink = NULL;
        adjList[i].VexInlink  = NULL;
    }
    for ( int i=0; i<VexNum*VexNum; ++i ){
        cin>>edgetemp;
        //edgetemp = b[i];
        if ( edgetemp==0 ){
            continue;
        }
 
        EdgeNode *pEdge = new EdgeNode;
        pEdge->HeadName =adjList[i/VexNum].name;
        pEdge->TailName =adjList[i%VexNum].name;
        pEdge->weight   = edgetemp;
 
        pEdge->VexOut   = adjList[i/VexNum].VexOutlink;
        if ( pEdge->VexOut ){
            while ( pEdge->VexOut->VexOut){
                pEdge->VexOut=pEdge->VexOut->VexOut;
            }
            pEdge->VexOut->VexOut =pEdge;
            pEdge->VexOut=NULL;
        } else {
            adjList[i/VexNum].VexOutlink =pEdge;
            pEdge->VexOut = NULL;
        }
    }
    for ( int i=0 ;i<VexNum ;++i ){
        EdgeNode **pInLink =&adjList[i].VexInlink;
        for ( int j=0; j<VexNum; ++j ){
            if ( i==j ){
                continue;
            }
            EdgeNode *p =adjList[j].VexOutlink;
            while ( p ){
                if ( p->TailName !=adjList[i].name ){
                    p = p->VexOut;
                    continue;
                }
                *pInLink = p;
                pInLink = &p->VexIn;
                p = p->VexOut;
            }
        }
        *pInLink = NULL;
    }
}
 
voiddestroyGrape()
{
    for ( int i=0; i<VexNum ;++i ){
        EdgeNode *p = adjList[i].VexOutlink;
        EdgeNode *q;
        while ( p ){
            q = p;
            p = p->VexOut;
            delete q;
        }
    }
 
 
}
 
voidprintGrape()
{
    for ( int i=0; i<VexNum; ++i ){
       cout<<adjList[i].name<<"-->";
        EdgeNode *p = adjList[i].VexOutlink;
        while ( p ){
           cout<<"("<<p->HeadName<<","<<p->TailName<<","<<p->weight<<")";
            p = p->VexOut;
        }
        cout<<endl;
        p = adjList[i].VexInlink;
       cout<<adjList[i].name<<"-->";
        while ( p ){
           cout<<"("<<p->HeadName<<","<<p->TailName<<","<<p->weight<<")";
            p = p->VexIn;
        }
        cout<<endl;
 
    }
}
 
voidtopologicRank()
{
    EdgeNode *pPre;
    EdgeNode *pNext;
    vexTopological *ptopo;
    stack<vexTopological*> s;
    deque<vexTopological*> sPrint;
    for ( int i=0; i<VexNum; ++i ){
        int vextopoNum    = 0;
        vextopo[i].name   = i+'A';
        vextopo[i].early  = 0;
        vextopo[i].last   = VEXMAX;
        vextopo[i].isUsed = false;
 
        pPre = adjList[i].VexInlink;
        while ( pPre ){
            pPre = pPre->VexIn;
            vextopoNum++;
        }
        vextopo[i].preVexNum = vextopoNum;
    }
 
    //按拓扑顺序压入栈中.
    for ( int i=0; i<VexNum; ++i  ){
        int topoNum = 0;
        while ( topoNum<VexNum && vextopo[topoNum].preVexNum
                  &&vextopo[topoNum].isUsed ){
            topoNum ++;
        }
        if ( topoNum == VexNum ){
            cout<<"hascycle"<<endl;
            return ;
        }
        topoNum = true;
        s.push(&vextopo[i]);
        sPrint.push_back(&vextopo[i]);
       
        pNext = adjList[i].VexOutlink;
        while ( pNext ){
            int nextNum =pNext->TailName-'A';
            if ( vextopo[nextNum].early <(vextopo[i].early + pNext->weight) ){
                vextopo[nextNum].early =vextopo[i].early + pNext->weight;
            }
            vextopo[nextNum].preVexNum--;
            pNext = pNext->VexOut;
        }   
    }
 
    ptopo = s.top();
    s.pop();
    ptopo->last = ptopo->early;
    s.push(ptopo);
    while ( !s.empty() ){
        int vexPos;
        int preVexPos;
 
        ptopo = s.top();
        s.pop();
       
        vexPos = ptopo->name-'A';
        pPre = adjList[vexPos].VexInlink;
        while ( pPre ){
            preVexPos = pPre->HeadName-'A';
            if ( vextopo[preVexPos].last >ptopo->last - pPre->weight ){
                vextopo[preVexPos].last  = ptopo->last - pPre->weight;
            }
            pPre = pPre->VexIn;
        }
    }
    while ( !sPrint.empty() ){
        vexTopological * p = sPrint.front();
        sPrint.pop_front();
        if ( p->early != p->last ){
            continue;
        }
        int vexPos = p->name - 'A';
        EdgeNode * pedge =adjList[vexPos].VexOutlink;
        while ( pedge ){
            if (vextopo[pedge->TailName-'A'].last == vextopo[pedge->TailName-'A'].early){
               cout<<"("<<pedge->HeadName<<","<<pedge->TailName<<","<<pedge->weight<<")";
            }
            pedge = pedge->VexOut;
        }
 
    }
}
 
int main()
{
    creatGraph();
    printGrape();
    topologicRank();
    destroyGrape();
}

《拓扑排序和关键路径》

测试数据:

《拓扑排序和关键路径》

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/u013009575/article/details/18978571
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞