2015.8.11
求每个活动最早发生时间,以及最晚发生时间。
最早发生时间等于最晚发生时间的那条路径就是关键路径。
所以,关键路径求解的关键思路在于:早发生时间,以及最晚发生时间的计算公式。
根据公式,最早发生时间是用拓扑排序来求。
最晚发生时间,是用倒过来的拓扑排序来求。
关键路径求解就是这么简单。
2016.01.11 - 2016.01.12
关键路径求解是建立在拓扑排序基础之上的,所以需要参考之前拓扑排序的代码。
在此基础上,更新entity:AGraph不变,ANode新添weight字段。
邻接表的创建也相应调整:
/** * create a graph of adjacency list */ public void CreateAgraph(AGraph G, int A[][], int pNum) { ANode p, pre = null; G.setN(pNum); G.setE(0); ANode[] arr = G.getHeadNode(); for (int i = 0; i < G.getN(); i++) { arr[i].setData(i); G.setHeadNode(arr); } for (int i = 0; i < G.getN(); i++) for (int j = 0; j < G.getN(); j++) if (A[i][j] != 0) { p = new ANode(); p.setWeight(A[i][j]); p.setData(j); arr[j].setIn(arr[j].getIn() + 1); if (null == arr[i].getNext()) arr[i].setNext(p); else pre.setNext(p); pre = p; G.setE(G.getE() + 1); } } /** * output the graph */ public void DispAGraph(AGraph g) { System.out.println("DispAGraph:"); int i; ANode p; ANode[] arr = g.getHeadNode(); for (i = 0; i < g.getN(); i++) { p = arr[i]; while (p != null) { System.out.print(p.getData() + "->"); p = p.getNext(); } System.out.println(); } }
改造之前的拓扑排序方法,使之可用于求etv。
/** * get etv by TopologySort */ private List<Integer> CPTopologySort(Stack<ANode> stack, AGraph g) { int VERTEX_NUM = g.getN(); List<Integer> etv = set0ofAllList(new ArrayList<Integer>(), VERTEX_NUM); ANode[] arr = g.getHeadNode(); // this array is the record of topology sort Boolean[] visit = new Boolean[VERTEX_NUM]; for (int i = 0; i < VERTEX_NUM; i++) visit[i] = false; Queue<ANode> queue = new LinkedList<ANode>(); // get the nodes which's in-degree is 0 and add them to the queue for (int i = 0; i < VERTEX_NUM; i++) if (0 == arr[i].getIn()) { visit[i] = true; queue.add(arr[i]); } System.out.println("topology sort:"); while (!queue.isEmpty()) { ANode temp = queue.peek(); ANode nextNode = temp.getNext(); while (null != nextNode) { int where = nextNode.getData(); // in-degree decremented by one arr[where].setIn(arr[where].getIn() - 1); // add the nodes which's in-degree is 0 and haven't been sorted // to the queue if (0 == arr[where].getIn() && false == visit[where]) { visit[where] = true; queue.add(arr[where]); } if (etv.get(temp.getData()) + nextNode.getWeight() > etv .get(where)) etv.set(where, etv.get(temp.getData()) + nextNode.getWeight()); nextNode = nextNode.getNext(); } ANode anode = queue.poll(); // get out of the queue and print the data System.out.print(anode.getData() + " "); stack.push(anode); } System.out.println(); return etv; }
主体关键路径算法,调用之前的拓扑排序算法求得的etv,求ltv,并使用etv和ltv求关键路径:
/** * get the critical path of AOE */ @Override public void CriticalPath(AGraph g) { Stack<ANode> stack = new Stack<ANode>(); List<Integer> etv = CPTopologySort(stack, g); outPutArrWithBlankLine(etv, "Output etv:"); // initialize ltv List<Integer> ltv = setArrWithSingleValue(new ArrayList<Integer>(), etv.get(etv.size() - 1),etv.size()); // get ltv while (!stack.isEmpty()) { ANode node = stack.pop(); ANode nextNode = node.getNext(); while (null != nextNode) { int k = nextNode.getData(); if (ltv.get(k) - nextNode.getWeight() < ltv.get(node.getData())) ltv.set(node.getData(), ltv.get(k) - nextNode.getWeight()); nextNode = nextNode.getNext(); } } outPutArrWithBlankLine(ltv, "Output ltv:"); ANode[] arr = g.getHeadNode(); ANode pe; System.out.println(); System.out.println("Output critical path:"); /* get the critical path of AOE */ for (int j = 0; j < g.getN(); j++) { for (pe = arr[j].getNext(); pe != null; pe = pe.getNext()) { int k = pe.getData(); int ete = etv.get(j); int lte = ltv.get(k) - pe.getWeight(); if (ete == lte) System.out.println("<v" + arr[j].getData() + " -v" + arr[k].getData() + "> length: " + pe.getWeight()); } } }
一些其它的private方法:
private List<Integer> set0ofAllList(List<Integer> list, int length) { for (int i = 0; i < length; i++) list.add(0); return list; } private void outPutArrWithBlankLine(List<Integer> etv, String instruction) { System.out.println(); System.out.println(instruction + etv); } private List<Integer> setArrWithSingleValue(List<Integer> arr, Integer value,int size) { arr.clear(); for (int i = 0; i < size; i++) arr.add(value); return arr; }
新的测试方法:
public class GraphTest1 { public static void main(String[] args) { System.out.println("creating adjacency list..."); int[][] array = new int[10][10]; for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) array[i][j] = 0; array[0][1] = 3; array[0][2] = 4; array[1][3] = 5; array[2][3] = 8; array[1][4] = 6; array[3][4] = 3; array[2][5] = 7; array[4][7] = 4; array[5][7] = 6; array[4][6] = 9; array[7][8] = 5; array[6][9] = 2; array[8][9] = 3; AGraph agraph = new AGraph(); ANode[] arr = new ANode[10]; for (int j = 0; j < 10; j++) arr[j] = new ANode(); agraph.setHeadNode(arr); GraphBasicService gbs = new GraphBasicServiceImpl(); gbs.CreateAgraph(agraph, array, 10); gbs.DispAGraph(agraph); System.out.println("count in-degree:"); ANode[] arr1 = agraph.getHeadNode(); for (int i = 0; i < agraph.getN(); i++) System.out.print(arr1[i].getIn() + " "); System.out.println(); gbs.CriticalPath(agraph); } }
测试结果: