aoe网最早开始时间和最迟开始时间_关键路径(AOE)网 通俗易懂
關(guān)鍵路徑
關(guān)鍵路徑是求「工程上時間最短的問題」的方法閱讀本文前請先了解
拓撲排序
拓撲排序主要解決「工程是否能順序進行」的問題,關(guān)鍵路徑在拓撲排序的基礎(chǔ)上解決「工程最短時間的問題」。
一、工程最短時間
工程時間最短的問題:
按照工廠上圖生產(chǎn)一輛汽車,外殼、發(fā)動機、輪子和其他部件可以同時建造。(1)求組裝完成最短需要多少時間?
(2)如何縮短最短時間?
答案:
(1)
因為所有部件可以同時建造,所以只要最長時間的「發(fā)動機」不建造完畢集中部件就無法進行。所以:「工程最短時間」就是通向匯點的和 最長的權(quán)重。(最長權(quán)重的路徑也叫做「關(guān)鍵路徑」)
上圖 開始 -> 發(fā)動機完成 -> 部件集中完成 -> 組裝完成 就是最長權(quán)重,組裝完成最短用時 6
(2)
關(guān)鍵路徑性質(zhì):縮短關(guān)鍵路徑上的時間就能縮短最短時間(但是縮短的同時關(guān)鍵路徑會動態(tài)發(fā)生變化,比如發(fā)動機建造時間 <= 2 ,繼續(xù)縮短發(fā)動機建造時間就沒用了)
二、AOE (Activity On Edge)網(wǎng)絡(luò)
找出最長權(quán)重的路徑就是關(guān)鍵路徑。所以邊必須有權(quán)重。(沒權(quán)重咋算??)
我們要在「拓撲排序」AOV 網(wǎng)的基礎(chǔ)上介紹 AOE 網(wǎng),區(qū)別如下
- AOV(Activity On Vertex):活動在頂點上,邊沒有權(quán)重
- AOE(Activity On Edge):活動在邊上,邊有權(quán)重
定義如下:
- 邊(Edge)稱之為「活動」(比如造輪子)
- 頂點(Vertex)稱之為「事件」(比如說輪子完成)
三、關(guān)鍵路基算法
3.1 關(guān)鍵路徑算法原理
我們?nèi)绾吻蟪鲫P(guān)鍵路徑?
我們舉個例子:小明有 2 個小時的作業(yè),回家一共有 4 個小時做作業(yè)的時間。他可以選擇一開始就做,或者因為「ddl 綜合征」最后 2 小時才開始做。此時「做作業(yè)最早的時間」和「做作業(yè)的最晚時間」是不等的。
老師知道小明的情況后將小明的作業(yè)增加到了 4 個小時的量,小明做作業(yè)的時間還是 4 個小時。小明只能回家就開始做作業(yè)才能做完。此時「做作業(yè)最早的時間」和「做作業(yè)的最晚時間」是相等的。
「做作業(yè)最早的時間」和「做作業(yè)的最晚時間」是相等的說明:如果做作業(yè)的時間延誤,將會導(dǎo)致整個工期延誤,做作業(yè)的時間縮短,整個工期的最短時間就會縮短。
我們將「做作業(yè)」抽象為「活動」Activity,「作業(yè)完成」抽象為「事件」Event
關(guān)鍵路徑定義:活動的最早發(fā)生時間和最晚發(fā)生時間相等的路徑就是關(guān)鍵路徑
求關(guān)鍵路徑我們只需要求出「活動最早發(fā)生時間」和「活動最晚發(fā)生時間」即可。
3.2 關(guān)鍵路徑算法
(1)參數(shù)定義
求關(guān)鍵路徑我們只需要求出「活動最早發(fā)生時間」和「活動最晚發(fā)生時間」即可。
但是在 AOE 圖中,「活動」就是向量邊,求向量邊一般是困難的,我們可以借助頂點來求邊。
參數(shù)定義如下:
- etv(Earliest Time of Vertex):頂點最早發(fā)生時間,也就是「事件最早發(fā)生時間」
- ltv(Lastest Time of Vertex):頂點最晚發(fā)生時間,也就是「事件最晚發(fā)生時間」
- ete(Earliest Time of Edge):邊最早發(fā)生時間,也就是「活動最早發(fā)生時間」
- lte(Lastest Time of Edge):邊最晚發(fā)生時間,也就是「活動最晚發(fā)生時間」
我們通過 etv 求 ete,ltv 求 lte
(2)算法步驟
步驟如下:(結(jié)合代碼理解)
- 通過拓撲排序求出 etv「事件最早發(fā)生時間」
etv[j] = max{etv(i) + weight}
- 通過「反向推導(dǎo)」求出 ltv「事件最晚發(fā)生時間」
ltv[i] = max{etv(j) - weight}
- 通過 etv 求出 ete「活動最早發(fā)生時間」
活動最早發(fā)生時間等于 from(箭頭開始方向的事件最早發(fā)動時間)
- 通過 ltv 求出 lte「活動最晚發(fā)生時間」
活動最晚發(fā)生時間等于 to - weight(箭頭結(jié)束方向的事件發(fā)生時間 - 權(quán)重)
- 通過 lte - ete 求出關(guān)鍵路徑
四、代碼
示例如下圖:
public class CriticalPath {/** 邊 */static class Edge{/** 權(quán)重 */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{/** 入度 數(shù)量 */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){//頂點數(shù)量int length = graph.size();//邊數(shù)量int numOfEdges = 0;for (Vertex vertex : graph) {Edge edge = vertex.firstEdge;while (edge!=null){numOfEdges ++;edge = edge.next;}}//事件最早發(fā)生時間int[] etv = new int[length];//事件最晚發(fā)生時間int[] ltv = new int[length];//活動最早發(fā)生時間int[] ete = new int[numOfEdges];//活動最晚發(fā)生時間int[] lte = new int[numOfEdges];//1. 通過拓撲排序求 etv 「事件最早發(fā)生時間」//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();//儲存拓撲排序后的結(jié)構(gòu)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 反向推導(dǎo)求出 ltv「事件最晚發(fā)生時間」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 求關(guān)鍵路徑 System.out.println("====關(guān)鍵路徑====");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);} }結(jié)果:
====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 ====關(guān)鍵路徑==== E1 E5 E8總結(jié)
以上是生活随笔為你收集整理的aoe网最早开始时间和最迟开始时间_关键路径(AOE)网 通俗易懂的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++builder启动了怎么停止_Ap
- 下一篇: c++ thread 内存泄漏_使用 T