Dynamic programming algorithm to find the shortest paths from every vertex to the goal vertex. Edges can have negative weights, but no negative-weight cycles (otherwise you could keep looping over a negative-weight cycle to get an infinitely negative number & shortest path would have no meaning). Dijkstra's fails for negative-wiehgt edges but Bellman-Ford can do it.
The shortest path between any 2 vertices uses at most n-1 edges (n=number of vertices). Since there cannot be any negative-weight cycles, any more than n-1 edges would only add to the total path cost so the algorithm stops when n-1 edges have been considered.
Bellman-Ford considers the shortest paths in increasing order of number of edges used starting from 0 edges (hence infinity for all but the goal node), then shortest paths using 1 edge, up to n-1 edges.
int[][][] graph
is an adjacency list for a weighted, directed graphgraph[0]
contains all edges FROM vertex0
- Each
graph[0][v]
is an edge as a 2D array containing[destinationVertex, edgeWeight]
- So for Graph 1,
graph[0]
is{ {1, 6}, {2, 7} },
meaning there are 2 edges FROM vertex0
:- (0 → 1) weight=6
- (0 → 2) weight=7
- Put an empty array
{}
in a row for a vertex that has no outgoing edges (see graph 2 for example)
String[] vertexNames
convert array index (e.g. 0, 1, 2, ...) to human-readable names
The Dynamic Programming deals with vertices asint
, but prints the final paths using this conversion arraystartingVertex
& agoalVertex
asint
. These indexes correspond tovertexNames[]
andgraph[][][]
, but S and T don't have to be the 1st & last items in the arrays, they don't even have to be called "S" and "T"
For Bellman-Ford, the last row is the most important. This final row holds cost of the shortest path from any vertex to the goal vertex using using at most n-1 edges. (A value is infinity if it cannot be reached)
Retracing the actual path is done using the successors[]
. Each entry in the memoization table also contains the next vertex in the path (or -1
if no path has been found).
Follow the path by looking 1 row above and at the column indicated by the successor. Stop when the goalVertex
is reached
- In
findShortestPaths
,i
is an edge counter representing how many edges can currently be included in the shortest path printTable()
displays "inf" for "infinity" because the underlying code usesInteger.MAX_VALUE
and 10-digit numbers mess up the column alignment when printingInteger.MAX_VALUE
represents infinity, but that requires some extra code to make sure overflow doesn't occur.
if(memoTable[i-1][destinationVertex] != Integer.MAX_VALUE)
This makes sure that the previous row's value is NOT infinity before adding theweight
of the new edge, otherwise it would result in a hugely negative numberpossiblePathCosts
holds costs of all possible paths coming FROM thesourceVertex
and also thesuccessor
where that path went. The minimum of all these paths 1 edge away fromsourceVertex
is chosen and thesuccessor
is also stored