001package algs44;
002import stdlib.*;
003import algs13.Stack;
004/* ***********************************************************************
005 *  Compilation:  javac FloydWarshall.java
006 *  Execution:    java FloydWarshall V E
007 *  Dependencies: AdjMatrixEdgeWeightedDigraph.java
008 *
009 *  Floyd-Warshall all-pairs shortest path algorithm.
010 *
011 *  % java FloydWarshall 100 500
012 *
013 *  Should check for negative cycles during triple loop; otherwise
014 *  intermediate numbers can get exponentially large.
015 *  Reference: "The Floyd-Warshall algorithm on graphs with negative cycles"
016 *  by Stefan Hougardy
017 *
018 *************************************************************************/
019
020public class XFloydWarshall {
021        private double[][] distTo;        // distTo[v][w] = length of    shortest v->w path
022        private DirectedEdge[][] edgeTo;  // edgeTo[v][w] = last edge on shortest v->w path
023
024        public XFloydWarshall(EdgeWeightedDigraph G) {
025                int V = G.V();
026                distTo = new double[V][V];
027                edgeTo = new DirectedEdge[V][V];
028
029                // initialize distances to infinity
030                for (int v = 0; v < V; v++) {
031                        for (int w = 0; w < V; w++) {
032                                distTo[v][w] = Double.POSITIVE_INFINITY;
033                        }
034                }
035
036                // initialize distances using edge-weighted digraph's
037                for (int v = 0; v < G.V(); v++) {
038                        for (DirectedEdge e : G.adj(v)) {
039                                distTo[e.from()][e.to()] = e.weight();
040                                edgeTo[e.from()][e.to()] = e;
041                        }
042                        // in case of self-loops
043                        if (distTo[v][v] >= 0.0) {
044                                distTo[v][v] = 0.0;
045                                edgeTo[v][v] = null;
046                        }
047                }
048
049                // Floyd-Warshall updates
050                for (int i = 0; i < V; i++) {
051                        // compute shortest paths using only 0, 1, ..., i as intermediate vertices
052                        for (int v = 0; v < V; v++) {
053                                if (edgeTo[v][i] == null) continue;    // optimization
054                                for (int w = 0; w < V; w++) {
055                                        if (distTo[v][w] > distTo[v][i] + distTo[i][w]) {
056                                                distTo[v][w] = distTo[v][i] + distTo[i][w];
057                                                edgeTo[v][w] = edgeTo[i][w];
058                                        }
059                                }
060                                if (distTo[v][v] < 0.0) return;  // negative cycle
061                        }
062                }
063        }
064
065        // is there a negative cycle?
066        public boolean hasNegativeCycle() {
067                for (int v = 0; v < distTo.length; v++)
068                        if (distTo[v][v] < 0.0) return true;
069                return false;
070        }
071
072        // negative cycle
073        public Iterable<DirectedEdge> negativeCycle() {
074                for (int v = 0; v < distTo.length; v++) {
075                        // negative cycle in v's predecessor graph
076                        if (distTo[v][v] < 0.0) {
077                                int V = edgeTo.length;
078                                EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V);
079                                for (int w = 0; w < V; w++)
080                                        if (edgeTo[v][w] != null)
081                                                spt.addEdge(edgeTo[v][w]);
082                                EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt);
083                                assert finder.hasCycle();
084                                return finder.cycle();
085                        }
086                }
087                return null;
088        }
089
090        // is there a path from v to w?
091        public boolean hasPath(int v, int w) {
092                return distTo[v][w] < Double.POSITIVE_INFINITY;
093        }
094
095
096        // return length of shortest path from v to w
097        public double dist(int v, int w) {
098                return distTo[v][w];
099        }
100
101        // return view of shortest path from v to w, null if no such path
102        public Iterable<DirectedEdge> path(int v, int w) {
103                if (!hasPath(v, w) || hasNegativeCycle()) return null;
104                Stack<DirectedEdge> path = new Stack<>();
105                for (DirectedEdge e = edgeTo[v][w]; e != null; e = edgeTo[v][e.from()]) {
106                        path.push(e);
107                }
108                return path;
109        }
110
111        // check optimality conditions
112        private boolean check(EdgeWeightedDigraph G, int s) {
113
114                // no negative cycle
115                if (!hasNegativeCycle()) {
116                        for (int v = 0; v < G.V(); v++) {
117                                for (DirectedEdge e : G.adj(v)) {
118                                        int w = e.to();
119                                        for (int i = 0; i < G.V(); i++) {
120                                                if (distTo[i][w] > distTo[i][v] + e.weight()) {
121                                                        System.err.println("edge " + e + " is eligible");
122                                                        return false;
123                                                }
124                                        }
125                                }
126                        }
127                }
128                return true;
129        }
130
131
132
133        public static void main(String[] args) {
134
135                // random graph with V vertices and E edges, parallel edges allowed
136                int V = Integer.parseInt(args[0]);
137                int E = Integer.parseInt(args[1]);
138                EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
139                for (int i = 0; i < E; i++) {
140                        int v = (int) (V * Math.random());
141                        int w = (int) (V * Math.random());
142                        double weight = Math.round(100 * (Math.random() - 0.15)) / 100.0;
143                        if (v == w) G.addEdge(new DirectedEdge(v, w, Math.abs(weight)));
144                        else        G.addEdge(new DirectedEdge(v, w, weight));
145                }
146
147                StdOut.println(G);
148
149                // run Floyd-Warshall algorithm
150                XFloydWarshall spt = new XFloydWarshall(G);
151
152                // print all-pairs shortest path distances
153                StdOut.format("     ");
154                for (int v = 0; v < G.V(); v++) {
155                        StdOut.format("%6d ", v);
156                }
157                StdOut.println();
158                for (int v = 0; v < G.V(); v++) {
159                        StdOut.format("%3d: ", v);
160                        for (int w = 0; w < G.V(); w++) {
161                                if (spt.hasPath(v, w)) StdOut.format("%6.2f ", spt.dist(v, w));
162                                else                   StdOut.format("   Inf ");
163                        }
164                        StdOut.println();
165                }
166
167                // print negative cycle
168                if (spt.hasNegativeCycle()) {
169                        StdOut.println("Negative cost cycle:");
170                        for (DirectedEdge e : spt.negativeCycle())
171                                StdOut.println(e);
172                        StdOut.println();
173                }
174
175                // print all-pairs shortest paths
176                else {
177                        for (int v = 0; v < G.V(); v++) {
178                                for (int w = 0; w < G.V(); w++) {
179                                        if (spt.hasPath(v, w)) {
180                                                StdOut.format("%d to %d (%5.2f)  ", v, w, spt.dist(v, w));
181                                                for (DirectedEdge e : spt.path(v, w))
182                                                        StdOut.print(e + "  ");
183                                                StdOut.println();
184                                        }
185                                        else {
186                                                StdOut.format("%d to %d          no path\n", v, w);
187                                        }
188                                }
189                        }
190                }
191
192        }
193
194}