拓扑排序和关键路径

一、拓扑排序

1、AOV网络
顶点活动网络(Activity On Vertex Network),即一个有向图G,各顶点表示活动,各条边表示活动之间的领先关系。
AOV网络是一个有向无环图。

2、拓扑排序算法
(1)在图中选择一个入度为0 的顶点,并输出之;
(2)从图中删除该顶点极其所有出边,借助栈或队列存储产生的新的入读为0 的顶点;
(3)重复(1)和(2)直至输出所有顶点。

3、代码

public void TopoSort(Graph graph, int[] order) {
        System.out.println("初始入度:");
        for (int i = 0; i < nodeNum; i++)
            System.out.print(inDegree[i] + " ");
        System.out.println();

        Queue<Node> queue = new LinkedList<>();

        for (int i = 0; i < nodeNum; i++) {
            if (inDegree[i] == 0) {
                // 入度为零的节点入队列
                queue.offer(vertex[i]);
            }
        }

        int count = 0, nextPos;
        for (int i = 0; i < nodeNum; i++) {
            if (!queue.isEmpty()) {
                Node node = queue.poll();
                order[count++] = node.id;
                // 将该节点的所有邻接点的入度减一
                while (node.next != null) {
                    node = node.next;
                    nextPos = getVertexPos(node.id);
                    inDegree[nextPos]--;
                    if (inDegree[nextPos] == 0)
                        queue.offer(vertex[nextPos]);
                }
            }
        }

        System.out.println("拓扑排序:");
        for (int i = 0; i < nodeNum; i++) {
            System.out.print(order[i] + " ");
        }
        System.out.println();
    }

执行结果

拓扑排序:
0 1 7 4 2 8 3 6 5 

二、关键路径

1、AOE网络
顶点表示事件,有向边表示活动,有向边的权值表示活动的所需时间,入边代表活动已完成,出边表示活动刚开始。

2、关键路径
完成工程所需的最短时间,即从开始顶点到完成顶点的最长路径的长度,该最长路径称为关键路径。

3、关键路径算法
(1)求事件可能的最早发生时间earliest[]

  • earliest(0) = 0
    earliest(j) = max{earliest(i) + w(i,j)}

(2)求时间允许的最迟发生时间latest[]

  • latest(n-1) = earliest(n-1)
    latest(i) = min{latest(j) - w(i,j)}

(3)求活动的最早开始时间和最迟发生时间early[]和late[]

  • early(k) = earlest(i)
    late(k) = latest(j) -w(i,j)
    当early[k] = late[k]时,对应的ak即为一个关键路径。

4、代码

    /**
     * 事件可能的最早发生时间
     * 
     * @param g
     * @param order
     * @param earliest
     */
    public void Earliest(Graph g, int[] order, int[] earliest) {
        int i, k;
        for (i = 0; i < nodeNum; i++) {
            earliest[i] = 0;
        }
        for (i = 0; i < nodeNum; i++) {
            k = order[i];
            Node node = vertex[getVertexPos(k)].next;
            while (node != null) {
                if (earliest[node.id] < earliest[k] + node.weight)
                    earliest[node.id] = earliest[k] + node.weight;
                node = node.next;
            }
        }
    }

    /**
     * 事件允许的最晚发生时间
     * 
     * @param g
     * @param order
     * @param earliest
     * @param latest
     */
    public void Latest(Graph g, int[] order, int[] earliest, int[] latest) {
        int i, j, k;
        for (i = 0; i < nodeNum; i++) {
            latest[i] = earliest[nodeNum - 1];
        }
        for (i = nodeNum - 2; i > -1; i--) {
            j = order[i];
            Node node = vertex[getVertexPos(j)].next;
            while (node != null) {
                k = node.id;
                if (latest[j] > latest[k] - node.weight)
                    latest[j] = latest[k] - node.weight;
                node = node.next;
            }
        }
    }

public void CriticalPath(Graph graph, int[] earliest, int[] latest) {
        int[] early = new int[edgeNum], late = new int[edgeNum];
        early[0] = earliest[0];
        early[1] = earliest[0];
        early[2] = earliest[0];
        early[3] = earliest[1];
        early[4] = earliest[2];
        early[5] = earliest[3];
        early[6] = earliest[4];
        early[7] = earliest[4];
        early[8] = earliest[5];
        early[9] = earliest[6];
        early[10] = earliest[7];

        late[0] = latest[1] - a[0];
        late[1] = latest[2] - a[1];
        late[2] = latest[3] - a[2];
        late[3] = latest[4] - a[3];
        late[4] = latest[4] - a[4];
        late[5] = latest[5] - a[5];
        late[6] = latest[6] - a[6];
        late[7] = latest[7] - a[7];
        late[8] = latest[7] - a[8];
        late[9] = latest[8] - a[9];
        late[10] = latest[8] - a[10];

        System.out.println("关键路径:");
        for (int i = 0; i < edgeNum; i++) {
            if (early[i] == late[i]) {
                System.out.print("a" + i + " ");
            }
        }
        System.out.println();
    }

执行结果

earliest:
0 6 4 5 7 7 16 15 19 
latest:
0 6 6 9 7 11 17 15 19 
early:
0 0 0 6 4 5 7 7 7 16 15 
late:
0 2 4 6 6 9 8 7 11 17 15 
关键路径:
a0 a3 a7 a10 
拓扑排序是一种对有向无环图进行排序的算法,它可以得到一个有向无环图的线性序列。在拓扑排序中,每个顶点表示一个任务,每个有向边表示一个任务之间的依赖关系,即如果任务A依赖于任务B,则在序列中任务A必须在任务B之后。拓扑排序可以用来解决很多实际问题,如编译器的依赖关系分析、任务调度等。 关键路径是指在一个有向无环图中,从源点到汇点的所有路径中,耗时最长路径称为关键路径关键路径上的任务称为关键任务,如果关键任务延迟了,整个项目的完成时间也会相应地延迟。因此,关键路径分析可以帮助我们找到项目中最关键的任务,以便优化项目进度。 拓扑排序的算法流程如下: 1. 统计每个顶点的入度(即有多少条边指向该顶点),并将入度为0的顶点加入队列。 2. 从队列中取出一个顶点,输出该顶点,并将该顶点的所有邻接点的入度减1。 3. 如果邻接点的入度为0,则将其加入队列。 4. 重复步骤2和3,直到队列为空。 关键路径的算法流程如下: 1. 对有向无环图进行拓扑排序,得到每个顶点的最早开始时间。 2. 从源点开始,按照拓扑序列依次计算每个顶点的最晚开始时间。 3. 对于每个任务,计算它的最早开始时间和最晚开始时间之差,即为该任务的总浮动时间。 4. 对于关键路径上的任务,它们的总浮动时间为0,因为它们不能延迟。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值