aoe网最早开始时间和最迟开始时间_关键路径(AOE)网 通俗易懂
生活随笔
收集整理的這篇文章主要介紹了
aoe网最早开始时间和最迟开始时间_关键路径(AOE)网 通俗易懂
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
關鍵路徑
關鍵路徑是求「工程上時間最短的問題」的方法閱讀本文前請先了解
拓撲排序
拓撲排序主要解決「工程是否能順序進行」的問題,關鍵路徑在拓撲排序的基礎上解決「工程最短時間的問題」。
一、工程最短時間
工程時間最短的問題:
按照工廠上圖生產一輛汽車,外殼、發動機、輪子和其他部件可以同時建造。(1)求組裝完成最短需要多少時間?
(2)如何縮短最短時間?
答案:
(1)
因為所有部件可以同時建造,所以只要最長時間的「發動機」不建造完畢集中部件就無法進行。所以:「工程最短時間」就是通向匯點的和 最長的權重。(最長權重的路徑也叫做「關鍵路徑」)
上圖 開始 -> 發動機完成 -> 部件集中完成 -> 組裝完成 就是最長權重,組裝完成最短用時 6
(2)
關鍵路徑性質:縮短關鍵路徑上的時間就能縮短最短時間(但是縮短的同時關鍵路徑會動態發生變化,比如發動機建造時間 <= 2 ,繼續縮短發動機建造時間就沒用了)
二、AOE (Activity On Edge)網絡
找出最長權重的路徑就是關鍵路徑。所以邊必須有權重。(沒權重咋算??)
我們要在「拓撲排序」AOV 網的基礎上介紹 AOE 網,區別如下
- AOV(Activity On Vertex):活動在頂點上,邊沒有權重
- AOE(Activity On Edge):活動在邊上,邊有權重
定義如下:
- 邊(Edge)稱之為「活動」(比如造輪子)
- 頂點(Vertex)稱之為「事件」(比如說輪子完成)
三、關鍵路基算法
3.1 關鍵路徑算法原理
我們如何求出關鍵路徑?
我們舉個例子:小明有 2 個小時的作業,回家一共有 4 個小時做作業的時間。他可以選擇一開始就做,或者因為「ddl 綜合征」最后 2 小時才開始做。此時「做作業最早的時間」和「做作業的最晚時間」是不等的。
老師知道小明的情況后將小明的作業增加到了 4 個小時的量,小明做作業的時間還是 4 個小時。小明只能回家就開始做作業才能做完。此時「做作業最早的時間」和「做作業的最晚時間」是相等的。
「做作業最早的時間」和「做作業的最晚時間」是相等的說明:如果做作業的時間延誤,將會導致整個工期延誤,做作業的時間縮短,整個工期的最短時間就會縮短。
我們將「做作業」抽象為「活動」Activity,「作業完成」抽象為「事件」Event
關鍵路徑定義:活動的最早發生時間和最晚發生時間相等的路徑就是關鍵路徑
求關鍵路徑我們只需要求出「活動最早發生時間」和「活動最晚發生時間」即可。
3.2 關鍵路徑算法
(1)參數定義
求關鍵路徑我們只需要求出「活動最早發生時間」和「活動最晚發生時間」即可。
但是在 AOE 圖中,「活動」就是向量邊,求向量邊一般是困難的,我們可以借助頂點來求邊。
參數定義如下:
- etv(Earliest Time of Vertex):頂點最早發生時間,也就是「事件最早發生時間」
- ltv(Lastest Time of Vertex):頂點最晚發生時間,也就是「事件最晚發生時間」
- ete(Earliest Time of Edge):邊最早發生時間,也就是「活動最早發生時間」
- lte(Lastest Time of Edge):邊最晚發生時間,也就是「活動最晚發生時間」
我們通過 etv 求 ete,ltv 求 lte
(2)算法步驟
步驟如下:(結合代碼理解)
- 通過拓撲排序求出 etv「事件最早發生時間」
etv[j] = max{etv(i) + weight}
- 通過「反向推導」求出 ltv「事件最晚發生時間」
ltv[i] = max{etv(j) - weight}
- 通過 etv 求出 ete「活動最早發生時間」
活動最早發生時間等于 from(箭頭開始方向的事件最早發動時間)
- 通過 ltv 求出 lte「活動最晚發生時間」
活動最晚發生時間等于 to - weight(箭頭結束方向的事件發生時間 - 權重)
- 通過 lte - ete 求出關鍵路徑
四、代碼
示例如下圖:
public class CriticalPath {/** 邊 */static class Edge{/** 權重 */int weight;/** 出度指向的點 */int toVertex;Edge next;public Edge(int weight, int toVertex, Edge next) {this.weight = weight;this.toVertex = toVertex;this.next = next;}}/** 頂點 */static class Vertex{/** 入度 數量 */int inNumber;/** 頂點信息 */Integer data;/** 第一條邊 */Edge firstEdge;public Vertex(int inNumber, Integer data, Edge firstEdge) {this.inNumber = inNumber;this.data = data;this.firstEdge = firstEdge;}}static void criticalPath(List<Vertex> graph){//頂點數量int length = graph.size();//邊數量int numOfEdges = 0;for (Vertex vertex : graph) {Edge edge = vertex.firstEdge;while (edge!=null){numOfEdges ++;edge = edge.next;}}//事件最早發生時間int[] etv = new int[length];//事件最晚發生時間int[] ltv = new int[length];//活動最早發生時間int[] ete = new int[numOfEdges];//活動最晚發生時間int[] lte = new int[numOfEdges];//1. 通過拓撲排序求 etv 「事件最早發生時間」//etvStack 用于儲存拓撲排序后的順序Stack<Vertex> etvStack = new Stack<>();//stack 用于拓撲排序Stack<Vertex> stack = new Stack<>();for (Vertex vertex : graph) {if (vertex.inNumber == 0){stack.push(vertex);}}while (!stack.isEmpty()){Vertex pop = stack.pop();//儲存拓撲排序后的結構etvStack.push(pop);//遍歷出度Edge edge = pop.firstEdge;while (edge != null){Vertex vertex = graph.get(edge.toVertex);vertex.inNumber --;if (vertex.inNumber == 0){stack.push(vertex);}//賦值更大的距離給 etvif (etv[pop.data] + edge.weight > etv[edge.toVertex]){etv[edge.toVertex] = etv[pop.data] + edge.weight;}edge = edge.next;}}//2.通過 etv 反向推導求出 ltv「事件最晚發生時間」System.out.println("====etv====");for (int i = 0; i < etv.length; i++) {System.out.print("V"+i +" = "+etv[i]+" ");}System.out.println();//初始化 ltvInteger endVertex = etvStack.peek().data;for (int i = 0; i < ltv.length; i++) {ltv[i] = etv[endVertex];}while (!etvStack.isEmpty()) {Vertex pop = etvStack.pop();Edge edge = pop.firstEdge;while (edge != null) {//賦值更小的距離給 ltvif (ltv[pop.data] > ltv[edge.toVertex] - edge.weight) {ltv[pop.data] = ltv[edge.toVertex] - edge.weight;}edge = edge.next;}}System.out.println("====ltv====");for (int i = 0; i < ltv.length; i++) {System.out.print("V"+i +" = "+ltv[i]+" ");}System.out.println();//3. 通過 etv 求 eteint index = 0;for (Vertex vertex : graph) {Edge edge = vertex.firstEdge;while (edge != null){ete[index++] = etv[vertex.data];edge = edge.next;}}System.out.println("====ete====");for (int i = 0; i < ete.length; i++) {System.out.print("E"+i +" = "+ete[i]+" ");}System.out.println();//4. 通過 ltv 求 lteindex = 0;for (Vertex vertex : graph) {Edge edge = vertex.firstEdge;while (edge != null){lte[index++] = ltv[edge.toVertex] - edge.weight;edge = edge.next;}}System.out.println("====lte====");for (int i = 0; i < lte.length; i++) {System.out.print("E"+i +" = "+lte[i]+" ");}System.out.println();//5. 用 lte - ete 求關鍵路徑 System.out.println("====關鍵路徑====");for (int i = 0; i < ete.length; i++) {if (lte[i] - ete[i] == 0) {System.out.print("E"+i+" ");}}return ;}/** 測試 */public static void main(String[] args) {char[] vertices = new char[]{'A','B','C','D','E','F','G'};Edge e3 = new Edge(2, 4, null);Edge e2 = new Edge(1, 3, e3);Edge e1 = new Edge(3, 2, e2);Edge e0 = new Edge(2, 1, e1);Edge e4 = new Edge(1, 5, null);Edge e5 = new Edge(1, 5, null);Edge e6 = new Edge(1, 5, null);Edge e7 = new Edge(1, 5, null);Edge e8 = new Edge(2, 6, null);Vertex a = new Vertex(0, 0, e0);Vertex b = new Vertex(1, 1, e4);Vertex c = new Vertex(1, 2, e5);Vertex d = new Vertex(1, 3, e6);Vertex e = new Vertex(1, 4, e7);Vertex f = new Vertex(4, 5, e8);Vertex g = new Vertex(1, 6, null);ArrayList<Vertex> graph = new ArrayList<>();graph.add(a);graph.add(b);graph.add(c);graph.add(d);graph.add(e);graph.add(f);graph.add(g);criticalPath(graph);} }結果:
====etv==== V0 = 0 V1 = 2 V2 = 3 V3 = 1 V4 = 2 V5 = 4 V6 = 6 ====ltv==== V0 = 0 V1 = 3 V2 = 3 V3 = 3 V4 = 3 V5 = 4 V6 = 6 ====ete==== E0 = 0 E1 = 0 E2 = 0 E3 = 0 E4 = 2 E5 = 3 E6 = 1 E7 = 2 E8 = 4 ====lte==== E0 = 1 E1 = 0 E2 = 2 E3 = 1 E4 = 3 E5 = 3 E6 = 3 E7 = 3 E8 = 4 ====關鍵路徑==== E1 E5 E8總結
以上是生活随笔為你收集整理的aoe网最早开始时间和最迟开始时间_关键路径(AOE)网 通俗易懂的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++builder启动了怎么停止_Ap
- 下一篇: 卸载unixodbc_完全卸载旧的uni