Floyd-Warshall: all shortest paths

前端 未结 2 1419
广开言路
广开言路 2021-02-04 07:47

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 the

2条回答
  •  我在风中等你
    2021-02-04 08:38

    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.

提交回复
热议问题