拓扑排序与关键路径(AOV网和AOE网)

一、AOV网(Activity On Vertex Network)

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网。

不能存在回路。

拓扑序列

设G(V,E)是一个具有n个顶点的有向图,V中的顶点序列满足若从顶点v~i~到v~j~有一条路径,则在顶点序列中v~i~必须在v~j~之前,称这样的一个顶点为拓扑序列。

二、拓扑排序算法

基本思路

从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的点为止。

AOV网要一直删除顶点,所以用邻接表表示图比较合适。考虑到算法中要查找入度为0的点,所以在原顶点结点中增加一个入度域即可。

代码如下:

    //拓扑排序
    private static boolean TopologicalSort(){
        EdgeNode edgeNode = new EdgeNode();
        int i,k;
        int gettop = 0;
        int top = 0;          //栈指针下标
        int count = 0;        //输出顶点的个数
        Stack<Integer> stack = new Stack<>();
        for(i = 0; i < adjList.verNum; i++){
            if(adjList.vertexNodes[i].in == 0) {
                stack.push(i);
            }
        }

        while (! stack.empty()){

            gettop = stack.pop();

            System.out.print(adjList.vertexNodes[gettop].data+" -> ");
            count++;
            for(edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next){
                k = edgeNode.adjvex;
                if(--adjList.vertexNodes[k].in == 0)
                    stack.push(k);
            }
        }

        return count >= adjList.verNum;
    }

三、AOE网

在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,称为AOE网(Activity On Edge Network)。

关键路径

路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫关键活动。

  • 在工程活动中,耗费的时间取决于关键路径的长度;
  • 拓扑排序解决了一个工程能否顺利进行的问题,关键路径解决了工程完成所需的最短时间问题。

算法基本思想

找到所有活动的最早开始时间和最晚开始时间,比较它们,如果相等就意味着此活动是关键活动,活动间的路径是关键路径,反之则不是。

代码如下:

 //求关键路径
    private static void CriticalPath(){
        ltv = new int[adjList.verNum];
        EdgeNode edgeNode = new EdgeNode();
        int i,gettop,j;
        int k = 0;
        int ete=0;
        int lte = 0;    //最早发生时间和最迟发生时间
        if(TopologicalSort()) {
            for (i = 0; i < adjList.verNum; i++) {
                ltv[i] = etv[adjList.verNum - 1];
            }

            while (!stack2.empty()) {
                gettop = stack2.pop();
                for (edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next) {
                    k = edgeNode.adjvex;
                    if (ltv[k] - edgeNode.weight < ltv[gettop]) {
                        ltv[gettop] = ltv[k] - edgeNode.weight;
                    }
                }
            }
            for (j = 0; j < adjList.verNum; j++) {
                for (edgeNode = adjList.vertexNodes[j].firstEdge; edgeNode != null; edgeNode = edgeNode.next) {
                    k = edgeNode.adjvex;
                    ete = etv[j];
                    lte = ltv[k] - edgeNode.weight;

                    if (ete == lte) {
                        System.out.printf("<v%d, v%d> length: %d \n ", j,k, edgeNode.weight);
                    }
                }
            }

        }
    }

    //拓扑排序
    private static boolean TopologicalSort(){
        etv = new int[adjList.verNum];
        EdgeNode edgeNode = new EdgeNode();
        int i,k;
        int gettop = 0;
        int count = 0;        //输出顶点的个数
        Stack<Integer> stack = new Stack<>();
        for(i = 0; i < adjList.verNum; i++){
            if(adjList.vertexNodes[i].in == 0) {
                stack.push(i);
            }
        }

        for (i = 0; i < adjList.verNum; i++){
            etv[i] = 0;
        }


        System.out.println("拓扑序列为:");
        while (! stack.empty()){

            gettop = stack.pop();

            System.out.print(adjList.vertexNodes[gettop].data+" -> ");
            count++;
            stack2.push(gettop);           // 拓扑序列压栈
            for(edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next){
                k = edgeNode.adjvex;
                if(--adjList.vertexNodes[k].in == 0)
                    stack.push(k);
                if(etv[gettop]+edgeNode.weight > etv[k]){                //求各顶点最早发生时间
                    etv[k] = etv[gettop] + edgeNode.weight;
                }
            }
        }
        System.out.println();

        return count >= adjList.verNum;
    }

时间复杂度为O(n+e),e为边数。

本文用到的代码链接

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