▶ 书中第四章部分程序,包括在加上自己补充的代码,无环图最短 / 最长路径通用程序,关键路径方法(critical path method)解决任务调度问题
● 无环图最短 / 最长路径通用程序
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Topological; 6 import edu.princeton.cs.algs4.DirectedEdge; 7 import edu.princeton.cs.algs4.EdgeWeightedDigraph; 8 import edu.princeton.cs.algs4.Stack; 9 10 public class class01 11 { 12 private double[] distTo; // 起点到各顶点的距离 13 private DirectedEdge[] edgeTo; // 引入各顶点时引入的边 14 15 public class01(EdgeWeightedDigraph G, int s) 16 { 17 distTo = new double[G.V()]; 18 edgeTo = new DirectedEdge[G.V()]; 19 for (int v = 0; v < G.V(); v++) 20 distTo[v] = Double.POSITIVE_INFINITY; // 求最长路径时改为 distTo[v] = Double.POSITIVE_INFINITY; 21 distTo[s] = 0.0; 22 Topological topological = new Topological(G); // 堆图 G 进行拓扑排序 23 if (!topological.hasOrder()) 24 throw new IllegalArgumentException(" <Constructor> Digraph is not acyclic. "); 25 for (int v : topological.order()) // 依照拓扑顺序松弛每条边 26 { 27 for (DirectedEdge e : G.adj(v)) 28 relax(e); 29 } 30 } 31 32 private void relax(DirectedEdge e) 33 { 34 int v = e.from(), w = e.to(); 35 if (distTo[w] > distTo[v] + e.weight()) // 加入这条边会使起点到 w 的距离变短 36 { // 求最长路径时将其改为 if (distTo[w] < distTo[v] + e.weight()) 37 distTo[w] = distTo[v] + e.weight(); // 确认加入该边 38 edgeTo[w] = e; 39 } 40 } 41 42 public double distTo(int v) 43 { 44 return distTo[v]; 45 } 46 47 public boolean hasPathTo(int v) 48 { 49 return distTo[v] < Double.POSITIVE_INFINITY;// 求最长路径时将其改为 return distTo[v] < Double.POSITIVE_INFINITY; 50 } 51 52 public Iterable<DirectedEdge> pathTo(int v) 53 { 54 if (!hasPathTo(v)) 55 return null; 56 Stack<DirectedEdge> path = new Stack<DirectedEdge>(); 57 for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) 58 path.push(e); 59 return path; 60 } 61 62 public static void main(String[] args) 63 { 64 In in = new In(args[0]); 65 int s = Integer.parseInt(args[1]); 66 EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); 67 class01 sp = new class01(G, s); 68 for (int v = 0; v < G.V(); v++) 69 { 70 if (sp.hasPathTo(v)) 71 { 72 StdOut.printf("%d to %d (%.2f) ", s, v, sp.distTo(v)); 73 for (DirectedEdge e : sp.pathTo(v)) 74 StdOut.print(e + " "); 75 StdOut.println(); 76 } 77 else 78 StdOut.printf("%d to %d no path ", s, v); 79 } 80 } 81 }
● 关键路径方法(critical path method)解决任务调度问题
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.AcyclicLP; 6 import edu.princeton.cs.algs4.DirectedEdge; 7 import edu.princeton.cs.algs4.EdgeWeightedDigraph; 8 9 public class class01 10 { 11 private class01() {} 12 13 public static void main(String[] args) 14 { 15 int n = StdIn.readInt(); // 任务数 16 int source = 2 * n; // 0 ~ n-1 为各任务起点,n ~ 2n-1 为各任务终点 17 int sink = 2 * n + 1; // 2n 为总起点,2n + 1 为总终点 18 EdgeWeightedDigraph G = new EdgeWeightedDigraph(2 * n + 2); 19 for (int i = 0; i < n; i++) 20 { 21 double duration = StdIn.readDouble(); // 第一列,任务耗时 22 G.addEdge(new DirectedEdge(source, i, 0.0)); // 总起点到任务起点的边 23 G.addEdge(new DirectedEdge(i + n, sink, 0.0)); // 任务终点到总终点的边 24 G.addEdge(new DirectedEdge(i, i + n, duration)); // 任务起点到任务终点的边 25 26 int m = StdIn.readInt(); // 以该任务完成为前提的其他任务数 27 for (int j = 0; j < m; j++) 28 { 29 int precedent = StdIn.readInt(); // 后续任务的编号 30 G.addEdge(new DirectedEdge(n + i, precedent, 0.0)); // 添加本任务终点到后续任务起点的边 31 } 32 } 33 34 AcyclicLP lp = new AcyclicLP(G, source); // 生成最长路径图,尽量选权值较大的边意味着尽量把任务往前靠 35 StdOut.println(" job start finish"); 36 StdOut.println("--------------------"); 37 for (int i = 0; i < n; i++) 38 StdOut.printf("%4d %7.1f %7.1f ", i, lp.distTo(i), lp.distTo(i + n)); 39 StdOut.printf("Finish time: %7.1f ", lp.distTo(sink)); 40 } 41 }