floyd_warshall
for each unordered pair (A,B)
seen = [] // empty set
min_paths[A,B] = fw_step(A,B)
fw_step A, B, seen
if min_paths[A,B] exists
return min_paths[A,B]
min_path = |A,B| // direct distance between nodes
// may be infinity
seen[A,B] += 1 // dictionary keyed by unordered pair
for each vertex K where seen[A,K] <= 1
and seen[B,K] <= 1
min_path = min(min_path,
fw_step(A,K,seen) + fw_step(K,B,seen))
return min_path
This is very inefficient. However, if we use an enumeration of all paths between A and B, based on the set of possible intermediate points [[], [0], [0,1], [0,1,2], ...], we can use that to remold the algorithm into an efficient dynamic programming solution:
for K in [1; vertices] // for every vertex K find the shortest path {K,A,B}
for A in [0; vertices) // that uses only [0..K-1] as intermediate nodes
for B in [0; vertices)
min_path[K, A, B] = min(min_path[K-1,A,B],
min_path[K-1,A,K-1] + min_path[K-1,K-1,B])
// minimal paths for every A,B are in min_path[vertices, A, B]
A simple and neat O(n^3) solution to a daunting problem! Note that because we are checking the distance between nodes so often, the algorithm is vastly more efficient when using adjacency matrices rather than adjacency lists or edge lists for our graphs. Also, since in every iteration we're only using the previous enumeration level, min_path need only be of size 2*vertices^2:
for K in [1; vertices]
for A in [0; vertices)
for B in [0; vertices)
min_path[K%2, A, B] = min(min_path[(K-1)%2,A,B],
min_path[(K-1)%2,A,K-1] + min_path[(K-1)%2,K-1,B])
// minimal paths for every A,B are in min_path[vertices%2, A, B]
Of course, this is overkill if you're only interested in the distance between two particular points - in that case, just use Dijkstra's algorithm, or some less general approach based on the specifics of your problem.An important thing to note is that since the algorithm prefers shorter paths, it immediately ignores paths with cycles and repetitions (at least in the absence of negative edges); thus, it is not immediately adaptable to finding the longest paths by replacing min() with max(). It is possible to modify it for that purpose, however that requires looking out for malformed paths.
No comments:
Post a Comment