Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Floyd-Warshall: all shortest paths

I've implemented Floyd-Warshall to return the distance of the shortest path between every pair of nodes/vertices and a single shortest path between each of these pairs.

Is there any way to get it to return every shortest path, even when there are multiple paths that are tied for shortest, for every pair of nodes? (I just want to know if I'm wasting my time trying)

like image 463
user1507844 Avatar asked Jul 06 '12 21:07

user1507844


People also ask

Is Floyd-Warshall better than Dijkstra?

Unlike Dijkstra's algorithm, Floyd Warshall can be implemented in a distributed system, making it suitable for data structures such as Graph of Graphs (Used in Maps). Lastly Floyd Warshall works for negative edge but no negative cycle, whereas Dijkstra's algorithm don't work for negative edges.

Can Floyd-Warshall algorithm for all pairs shortest path problem be used on a graph which contains a few negative weighted edges but no negative weight cycle?

Floyd Warshall's all pairs shortest paths algorithm works for graphs with negative edge weights because the correctness of the algorithm does not depend on edge's weight being non-negative, while the correctness of Dijkstra's algorithm is based on this fact.

Which algorithm uses all pairs shortest path problem * Warshall's algorithm Floyd's algorithm Dijkstra's algorithm Kruskal's algorithm?

Floyd-Warshall algorithm It is used to find all pair shortest path problem from a given weighted graph.


2 Answers

If you just need the count of how many different shortest path exist, you can keep a count array in addition to the shortestPath array. Here's is a quick modification of the pseudocode from wiki.

procedure FloydWarshall ()
    for k := 1 to n
        for i := 1 to n
            for j := 1 to n
                if path[i][j] == path[i][k]+path[k][j] and k != j and k != i
                    count[i][j] += 1;
                else if path[i][j] > path[i][k] + path[k][j]
                    path[i][j] = path[i][k] + path[k][j]
                    count[i][j] = 1

If you need a way to find all the paths, you can store a vector/arraylist like structure for each pair to expand and collapse. Here is a modification of the pseudocode from the same wiki.

procedure FloydWarshallWithPathReconstruction ()
    for k := 1 to n
        for i := 1 to n
            for j := 1 to n
                if path[i][k] + path[k][j] < path[i][j]
                    path[i][j] := path[i][k]+path[k][j];
                    next[i][j].clear()
                    next[i][j].push_back(k) // assuming its a c++ vector
                else if path[i][k] + path[k][j] == path[i][j] and path[i][j] != MAX_VALUE and k != j and k != i
                    next[i][j].push_back(k)

Note: if k==j or k==i, that means, you're checking either path[i][i]+path[i][j] or path[i][j]+path[j][j], both should be equal to path[i][j] and that does not get pushed into next[i][j].

Path reconstruction should be modified to handle the vector. The count in this case would be each vector's size. Here is a modification of the pseudocode (python) from the same wiki.

procedure GetPath(i, j):
    allPaths = empty 2d array
    if next[i][j] is not empty:
        for every k in next[i][j]:
            if k == -1: // add the path = [i, j]
                allPaths.add( array[ i, j] ) 
            else: // add the path = [i .. k .. j]
                paths_I_K = GetPath(i,k) // get all paths from i to k
                paths_K_J = GetPath(k,j) // get all paths from k to j
                for every path between i and k, i_k in paths_I_K:
                    for every path between k and j, k_j in paths_K_J:
                        i_k = i_k.popk() // remove the last element since that repeats in k_j
                        allPaths.add( array( i_k + j_k) )

    return allPaths

Note: path[i][j] is an adjacency list. While initializing path[i][j], you can also initialize next[i][j] by adding a -1 to the array. For instance an initialization of next[i][j] would be

for every edge (i,j) in graph:
   next[i][j].push_back(-1)

This takes care of an edge being the shortest path itself. You'll have to handle this special case in the path reconstruction, which is what i'm doing in GetPath.

Edit: "MAX_VALUE" is the initialized value in the array of distances.

like image 124
deebee Avatar answered Sep 29 '22 20:09

deebee


The 'counting' function in the current approved answer flails in some cases. A more complete solution would be:

procedure FloydWarshallWithCount ()
for k := 1 to n
    for i := 1 to n
        for j := 1 to n
            if path[i][j] == path[i][k]+path[k][j]
                count[i][j] += count[i][k] * count[k][j]
            else if path[i][j] > path[i][k] + path[k][j]
                path[i][j] = path[i][k] + path[k][j]
                count[i][j] = count[i][k] * count[k][j]

The reason for this is that for any three vertices i, j, and k, there may be multiple shortest paths that run from i through k to j. For instance in the graph:

       3             1
(i) -------> (k) ---------> (j)
 |            ^
 |            |
 | 1          | 1
 |     1      |
(a) -------> (b)

Where there are two paths from i to j through k. count[i][k] * count[k][j] finds the number of paths from i to k, and the number of paths from k to j, and multiplies them to find the number of paths i -> k -> j.

like image 43
user4336087 Avatar answered Sep 29 '22 20:09

user4336087