4

Is it possible to modify Floyd-Warshall algorithm when solving the shortest path problem for a directed weighted graph with n nodes, such that each shortest path have no more than m steps? More precisely, for each pair of nodes i and j, you are about to find the shortest directed path from i to j that contains no more than m nodes. Does time complexity still remain O(n3)?

user3598743
  • 61
  • 1
  • 4
  • I can't think of a way to do it in less than O(n^3m^2) time. (Essentially: use DP to calculate each value of f(i, j, k, w), where this function represents the shortest path from i to j using only vertices <= k and having total edge count <= w. The extra m factor is because you need to loop over all m+1 ways to split the edge count on either side of the (k+1)th vertex when you consider paths that go via it.) – j_random_hacker May 04 '14 at 00:52
  • It's slow for the problem I need to solve. Recently, using [min-plus matrix multiplication](https://en.wikipedia.org/wiki/Min-plus_matrix_multiplication), I've implemented m-edges all-pairs-shortest-paths algorithm with maximum of _m_ edges in O(n^3*log(n)) time. – user3598743 May 05 '14 at 00:44
  • I'm interested to see your approach -- could you write it up as an answer? (This is allowed, even encouraged on SO.) I can't see how you avoid getting m as a factor in the running time with this approach, since each matrix multiplication takes O(n^3) time (or at least O(n^2.something), and you may need up to m of them. Even so this could still save a factor of m over my way. – j_random_hacker May 05 '14 at 01:18
  • Actually if you meant O(n^3*log(m)) then I can potentially see how it might work: use repeated squaring to drop the max number of iterations from m down to log m. Is that right? A write-up would still be awesome :) – j_random_hacker May 05 '14 at 01:22
  • Yup, you'are right! :) Sure, I'll write it then as an answer. – user3598743 May 05 '14 at 10:45

3 Answers3

2

Meanwhile, I found an O(n3logm) algorithm for finding all-pairs shortest paths (ASPP) problem for the graph with n nodes such that no path contain more than m nodes.

Given two n x n matrices, say A = [aij] and B = [bij], their distance product is n x n matrix C = [cij] = A x B, defined by cij = min1≤kn {aik + bkj}.

This is related to the ASPP in the following way. Given weighted matrix E of distances in the graph, En is matrix of all-pairs shortest path. If we add constraint that no path contains more than m nodes, then matrix Em is the solution to ASPP. Since calculating power can be found in O(logm) time, this gives us an O(n3logm) algorithm.

Here, one may find faster algorithms for calculating distance product of matrices in some special cases, but the trivial one O(n3) is enough for me, since overall time is almost as fast as Floyd-Warshall approach.

user3598743
  • 61
  • 1
  • 4
  • Nice. At first I thought this would only compute the shortest path using *exactly* m edges, but then I realised that it computes the shortest path using exactly m edges *in which any number of those edges may be "self-edges" of cost 0*, so it does in fact compute all shortest paths using *up to* m edges :) – j_random_hacker May 05 '14 at 20:50
0

Yes and Yes.

  • Each iteration of the algotithm adds a single unit of length of the paths you search for. So if you limit the iterations to m then you find a path of length at most m.
  • The complexity will remain O(n^3) in the worst case of m -> n. However, more precise estimate would be O(m * n^2).
Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
  • I might haven't got it well, how do I limit iterations to _m_? Do you mean to change the first line of the code from `for k = 1 to n do` to `for k = 1 to m do`? In that case, complexity is reduced as you said, but only first _m_ nodes of the graph are considered when finding the shortest path between each pair of nodes. – user3598743 May 03 '14 at 15:33
  • Ah sorry, i was thinking of the Bellman Ford algorithm it seems: http://en.m.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm – Boris Strandjev May 03 '14 at 18:41
0

I believe that this could be done with a different data structure (one that would allow you to keep track of the number of steps)?

Since usually Floyd-Warshall is done with a connectivity matrix (where matrix [j][k] represents the distance between nodes j and k), instead of making that matrix an integer we can make it a struct that has two integers : the distance between two nodes and the number of steps between them.

I wrote up something in C++ to explain what I mean :

#define INFINITY 9999999

struct floydEdge
{
    int weight;
    int steps;
};

floydEdge matrix[10][10];

int main()
{
    //We initialize the matrix
    for(int j=0;j<10;j++)
    {
        for(int k=0;k<10;k++)
        {
            matrix[j][k].weight=INFINITY;
            matrix[j][k].steps=0;
        }
    }

    //We input some weights
    for(int j=0;j<10;j++)
    {
        int a, b;
        cin>>a>>b;
        cin>>matrix[a][b].weight;
        matrix[b][a].weight=matrix[a][b].weight;
        matrix[a][b].steps=matrix[b][a].steps=1;
    }

    //We do the Floyd-Warshall, also checking for the step count as well as the weights
    for(int j=0;j<10;j++)
    {
        for(int k=0;k<10;k++)
        {
            for(int i=0;i<10;i++)
            {
                //We check if there is a shorter path between nodes j and k, using the node i. We also check if that path is shorter or equal to 4 steps.
                if((matrix[j][k].weight > matrix[j][i].weight + matrix[i][k].weight) && (matrix[j][i].steps+matrix[i][k].steps<=4))
                {
                    matrix[j][k].weight=matrix[k][j].weight=matrix[j][i].weight + matrix[i][k].weight;
                    matrix[j][k].steps=matrix[k][j].steps=matrix[j][i].steps+matrix[i][k].steps;
                }
                //If the path is not shorter, we can also check if the path is equal BUT requires less steps than the path we currently have.
                else if((matrix[j][k].weight == matrix[j][i].weight + matrix[i][k].weight) && (matrix[j][i].steps+matrix[i][k].steps<matrix[j][k].steps))
                {
                    matrix[j][k].weight=matrix[k][j].weight=matrix[j][i].weight + matrix[i][k].weight;
                    matrix[j][k].steps=matrix[k][j].steps=matrix[j][i].steps+matrix[i][k].steps;
                }
            }
        }
    }
    return 0;
}

I believe (but I am not completely sure) this works perfectly (always giving the shortest paths for between all nodes). Give it a try and let me know!

A. Andevski
  • 437
  • 1
  • 5
  • 17
  • 2
    I'm afraid this won't give optimal answers all the time: it might be that for some pair of vertices j and k, even though the shortest path via i requires more than 4(!) steps, there is *another path via i* that requires 4 or fewer steps, but which is still better than all paths between j and k that avoid i. – j_random_hacker May 04 '14 at 01:07
  • 2
    E.g. suppose there are 6 vertices j=v1, v2, i=v3, v4, v5, k=v6, with an edge of weight 2 between each vertex and the next, as well as an edge of weight 5 between j and i, and an edge of weight 12 between j and k. Then the shortest j->k path goes via i and has 5 edges with a total weight of 10, but this has too many edges so your algorithm will ignore it *and all j->k paths that visit i*, preferring the shortest i-avoiding path, which is the single edge j->k with weight 12. But this ignores the 4-edge path j->i->v4->v5->k with a lower total weight of 11. – j_random_hacker May 04 '14 at 01:14