《算法》第四章部分程序 part 19

▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径

● 有边权有向图的邻接矩阵

  1 package package01;
  2 
  3 import java.util.Iterator;
  4 import java.util.NoSuchElementException;
  5 import edu.princeton.cs.algs4.StdOut;
  6 import edu.princeton.cs.algs4.StdRandom;
  7 import edu.princeton.cs.algs4.DirectedEdge;
  8 
  9 public class class01
 10 {
 11     private static final String NEWLINE = System.getProperty("line.separator");
 12 
 13     private final int V;
 14     private int E;
 15     private DirectedEdge[][] adj;
 16 
 17     public class01(int inputV)
 18     {
 19         if (inputV < 0)
 20             throw new IllegalArgumentException("\n<Constructor> V < 0.\n");
 21         V = inputV;
 22         E = 0;
 23         adj = new DirectedEdge[V][V];
 24     }
 25 
 26     public class01(int inputV, int inputE)
 27     {
 28         this(inputV);
 29         if (inputE < 0 || inputE > V*V)
 30             throw new IllegalArgumentException("\n<Constructor> E < 0 || E > V*V.\n");
 31 
 32         for (E = 0; E != inputE;)
 33         {
 34             int v = StdRandom.uniform(V), w = StdRandom.uniform(V);
 35             double weight = Math.round(100 * StdRandom.uniform()) / 100.0;
 36             addEdge(new DirectedEdge(v, w, weight));
 37         }
 38     }
 39 
 40     public int V()
 41     {
 42         return V;
 43     }
 44 
 45     public int E()
 46     {
 47         return E;
 48     }
 49 
 50     public void addEdge(DirectedEdge e)
 51     {
 52         int v = e.from();
 53         int w = e.to();
 54         if (adj[v][w] == null)
 55         {
 56             E++;
 57             adj[v][w] = e;
 58         }
 59     }
 60 
 61     public Iterable<DirectedEdge> adj(int v)
 62     {
 63         return new AdjIterator(v);
 64     }
 65 
 66     private class AdjIterator implements Iterator<DirectedEdge>, Iterable<DirectedEdge>
 67     {
 68         private int v;
 69         private int w = 0;
 70 
 71         public AdjIterator(int inputV)
 72         {
 73             v = inputV;
 74         }
 75 
 76         public Iterator<DirectedEdge> iterator()
 77         {
 78             return this;
 79         }
 80 
 81         public boolean hasNext()    // 同一行里还有元素(还有以该顶点为起点的边)
 82         {
 83             for (; w < V; w++)
 84             {
 85                 if (adj[v][w] != null)
 86                     return true;
 87 
 88             }
 89             return false;
 90         }
 91 
 92         public DirectedEdge next()
 93         {
 94             if (!hasNext())
 95                 throw new NoSuchElementException();
 96             return adj[v][w++];
 97         }
 98 
 99         public void remove()
100         {
101             throw new UnsupportedOperationException();
102         }
103     }
104 
105     public String toString()
106     {
107         StringBuilder s = new StringBuilder();
108         s.append(V + " " + E + NEWLINE);
109         for (int v = 0; v < V; v++)
110         {
111             s.append(v + ": ");
112             for (DirectedEdge e : adj(v))
113                 s.append(e + "  ");
114             s.append(NEWLINE);
115         }
116         return s.toString();
117     }
118 
119     public static void main(String[] args)
120     {
121         int V = Integer.parseInt(args[0]);
122         int E = Integer.parseInt(args[1]);
123         class01 G = new class01(V, E);
124         StdOut.println(G);
125     }
126 }

● FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径

  1 package package01;
  2 
  3 import edu.princeton.cs.algs4.StdOut;
  4 import edu.princeton.cs.algs4.StdRandom;
  5 import edu.princeton.cs.algs4.DirectedEdge;
  6 import edu.princeton.cs.algs4.EdgeWeightedDigraph;
  7 import edu.princeton.cs.algs4.EdgeWeightedDirectedCycle;
  8 import edu.princeton.cs.algs4.Stack;
  9 import edu.princeton.cs.algs4.AdjMatrixEdgeWeightedDigraph;
 10 
 11 public class class01
 12 {
 13     private boolean hasNegativeCycle;  // 是否有负环
 14     private double[][] distTo;         // 从 v 到 w 的最短路径记作 distTo[v][w]
 15     private DirectedEdge[][] edgeTo;   // 从 v 到 w 的最短路径的最后一条边记作 edgeTo[v][w]
 16 
 17     public class01(AdjMatrixEdgeWeightedDigraph G)
 18     {
 19         int V = G.V();
 20         distTo = new double[V][V];
 21         edgeTo = new DirectedEdge[V][V];
 22         for (int v = 0; v < V; v++)     // 邻接表元素初始化为正无穷
 23         {
 24             for (int w = 0; w < V; w++)
 25                 distTo[v][w] = Double.POSITIVE_INFINITY;
 26         }
 27         for (int v = 0; v < G.V(); v++)
 28         {
 29             for (DirectedEdge e : G.adj(v))     // 添加以 v 为起点的各条边
 30             {
 31                 distTo[e.from()][e.to()] = e.weight();
 32                 edgeTo[e.from()][e.to()] = e;
 33             }
 34             if (distTo[v][v] >= 0.0)            // 自环归零
 35             {
 36                 distTo[v][v] = 0.0;
 37                 edgeTo[v][v] = null;
 38             }
 39         }
 40         for (int i = 0; i < V; i++)             // 循环 V 次
 41         {
 42             for (int v = 0; v < V; v++)         // 用 0 ~ i 作为中间顶点,尝试将其引入
 43             {
 44                 if (edgeTo[v][i] == null)       // v 不可达 i,跳过
 45                     continue;
 46                 for (int w = 0; w < V; w++)
 47                 {
 48                     if (distTo[v][w] > distTo[v][i] + distTo[i][w]) // 引入顶点 i 使得 v 到 w 的距离缩短
 49                     {
 50                         distTo[v][w] = distTo[v][i] + distTo[i][w]; // 正式引入顶点 i
 51                         edgeTo[v][w] = edgeTo[i][w];
 52                     }
 53                 }
 54                 if (distTo[v][v] < 0.0)         // 检测负环,条件是某顶点到自身的最短路径小于 0
 55                 {
 56                     hasNegativeCycle = true;
 57                     return;
 58                 }
 59             }
 60         }
 61     }
 62 
 63     public boolean hasNegativeCycle()
 64     {
 65         return hasNegativeCycle;
 66     }
 67 
 68     public Iterable<DirectedEdge> negativeCycle()
 69     {
 70         for (int v = 0; v < distTo.length; v++)
 71         {
 72             if (distTo[v][v] < 0.0)
 73             {
 74                 int V = edgeTo.length;
 75                 EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V);
 76                 for (int w = 0; w < V; w++)         // 把与 v 有关的边加入一个含边权有向图,用类 EdgeWeightedDirectedCycle 寻找环
 77                 {
 78                     if (edgeTo[v][w] != null)       // 实际上所有从 v 延伸出去的最短路径的边都加上了
 79                         spt.addEdge(edgeTo[v][w]);
 80                 }
 81                 EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt);
 82                 return finder.cycle();
 83             }
 84         }
 85         return null;
 86     }
 87 
 88     public boolean hasPath(int s, int t)
 89     {
 90 
 91         return distTo[s][t] < Double.POSITIVE_INFINITY;
 92     }
 93 
 94     public double dist(int s, int t)
 95     {
 96         if (hasNegativeCycle())
 97             throw new UnsupportedOperationException("\n<dist> Negative cost cycle exists.\n");
 98         return distTo[s][t];
 99     }
100 
101     public Iterable<DirectedEdge> path(int s, int t)
102     {
103         if (hasNegativeCycle())
104             throw new UnsupportedOperationException("\n<Iterable> Negative cost cycle exists.\n");
105         if (!hasPath(s, t))
106             return null;
107         Stack<DirectedEdge> path = new Stack<DirectedEdge>();
108         for (DirectedEdge e = edgeTo[s][t]; e != null; e = edgeTo[s][e.from()])
109             path.push(e);
110         return path;
111     }
112 
113     public static void main(String[] args)
114     {
115         int V = Integer.parseInt(args[0]);
116         int E = Integer.parseInt(args[1]);
117         AdjMatrixEdgeWeightedDigraph G = new AdjMatrixEdgeWeightedDigraph(V);
118         for (int i = 0; i < E; i++)
119         {
120             int v = StdRandom.uniform(V);
121             int w = StdRandom.uniform(V);
122             double weight = Math.round(100 * (StdRandom.uniform() - 0.15)) / 100.0;
123             if (v == w) G.addEdge(new DirectedEdge(v, w, Math.abs(weight)));
124             else G.addEdge(new DirectedEdge(v, w, weight));
125         }
126 
127         StdOut.println(G);
128         class01 spt = new class01(G);
129         StdOut.printf("  ");
130         for (int v = 0; v < G.V(); v++)
131             StdOut.printf("%6d ", v);
132         StdOut.println();
133         for (int v = 0; v < G.V(); v++)
134         {
135             StdOut.printf("%3d: ", v);
136             for (int w = 0; w < G.V(); w++)
137             {
138                 if (spt.hasPath(v, w))
139                     StdOut.printf("%6.2f ", spt.dist(v, w));
140                 else
141                     StdOut.printf("  Inf ");    // 存在负环的路径长度显示为负无穷
142             }
143             StdOut.println();
144         }
145         if (spt.hasNegativeCycle())             // 有负环单独显示,否则正常显示各条最短路径
146         {
147             StdOut.println("Negative cost cycle:");
148             for (DirectedEdge e : spt.negativeCycle())
149                 StdOut.println(e);
150             StdOut.println();
151         }
152         else
153         {
154             for (int v = 0; v < G.V(); v++)
155             {
156                 for (int w = 0; w < G.V(); w++)
157                 {
158                     if (spt.hasPath(v, w)) {
159                         StdOut.printf("%d to %d (%5.2f)  ", v, w, spt.dist(v, w));
160                         for (DirectedEdge e : spt.path(v, w))
161                             StdOut.print(e + "  ");
162                         StdOut.println();
163                     }
164                     else
165                         StdOut.printf("%d to %d no path\n", v, w);
166                 }
167             }
168         }
169     }
170 }

猜你喜欢

转载自www.cnblogs.com/cuancuancuanhao/p/9836349.html