All Pair Shortest Path Algorithm Using Dynamic Programming Example

Given a set of vertices V in a weighted graph where its edge weights w(u, v) can be negative, find the shortest path weights d(s, v) from every source s for all vertices v present in the graph. If the graph contains a negative-weight cycle, report it.

For example, consider the following graph:

Floyd Warshall Algorithm

The adjacency matrix containing the shortest distance is:

  0  -1  -2   0
4   0   2   4
5   1   0   2
3  -1   1   0

The shortest path from:

• vertex 0 to vertex 1 is [0 —> 2 —> 3 —> 1]
• vertex 0 to vertex 2 is [0 —> 2]
• vertex 0 to vertex 3 is [0 —> 2 —> 3]
• vertex 1 to vertex 0 is [1 —> 0]
• vertex 1 to vertex 2 is [1 —> 0 —> 2]
• vertex 1 to vertex 3 is [1 —> 0 —> 2 —> 3]
• vertex 2 to vertex 0 is [2 —> 3 —> 1 —> 0]
• vertex 2 to vertex 1 is [2 —> 3 —> 1]
• vertex 2 to vertex 3 is [2 —> 3]
• vertex 3 to vertex 0 is [3 —> 1 —> 0]
• vertex 3 to vertex 1 is [3 —> 1]
• vertex 3 to vertex 2 is [3 —> 1 —> 0 —> 2]

We have already covered single-source the shortest paths in separate posts. We have seen that:

  • For graphs having non-negative edge weights, Dijkstra's Algorithm runs in O(E + V × log(V))
  • For graphs containing negative edge weights, Bellman–Ford runs in O(V × E).
  • For a DAG, one pass of Bellman–Ford (called relaxation step) is enough that will take O(V + E) time.

Here, V is the total number of vertices and E is the total number of edges in the graph.


This post will introduce All-Pairs Shortest Paths that return the shortest paths between every pair of vertices in the graph containing negative edge weights.

Practice this problem

If the graph contains only positive edge weights, a simple solution would be to run Dijkstra's algorithm V times. The time complexity of this solution would be O(V × (E + V × log(V))), i.e., O(V × E + V2.log(V)).

If the graph contains negative edge weights, we can run Bellman–Ford once from each vertex to find all-pairs shortest paths. The time complexity of this approach will be O(V2 × E). If the graph is dense, i.e., E = V2 , then the time complexity becomes O(V4).

Floyd–Warshall algorithm is an algorithm for finding the shortest paths in a weighted graph with positive or negative edge weights (but with no negative cycles). It does so by comparing all possible paths through the graph between each pair of vertices and that too with O(V3) comparisons in a graph.

Following is the pseudocode for Floyd Warshall, as given on Wikipedia. The implementation takes a graph, represented by an adjacency matrix, and fills dist[] with shortest path (the least-cost) information:

let dist be V × V matrix of minimum distances initialized to INFINITY
for each vertex v
dist[v][v] = 0
for each edge (u, v)
dist[u][v] = weight(u, v)

for k from 0 to |V| – 1
for i from 0 to |V| – 1
for j from 0 to |V| – 1
if (dist[i][k] + dist[k][j]) is less than dist[i][j] then
dist[i][j] = dist[i][k] + dist[k][j]

Above pseudocode picks up a vertex k between 0 and V-1, one at a time, and include that vertex as an intermediate vertex in the shortest path between every pair of edges i—>j in the graph. It updates the cost matrix whenever a more straightforward path from i to j through vertex k is found. Since, for a given k, we have already considered vertices 0…k-1 as intermediate vertices, this approach works.


Let's consider the above graph,

Before the first iteration of the outer loop for k, the only known paths correspond to the single edges in the graph.


Floyd Warshall

At k = 0, paths that go through the vertex 0 are found: in particular, the path [1, 0, 2] is found, replacing the path [1, 2] which has fewer edges but is costly.

Floyd Warshall Algorithm: Step 0

At k = 1, paths going through the vertices {0, 1} are found. The following figure shows how the path [3, 1, 0, 2] is assembled from the two known paths [3, 1] and [1, 0, 2] encountered in previous iterations, with 1 in the intersection. The path [3, 1, 2] is not considered because [1, 0, 2] is the shortest path encountered so far from 1 to 2.

Floyd Warshall Algorithm: Step 1

At k = 2, paths going through the vertices {0, 1, 2} are found.

Floyd Warshall Algorithm: Step 2

Finally, at k = 3, all shortest paths are found.

Floyd Warshall Algorithm: Step 3

The Floyd–Warshall algorithm is simple to code and really efficient traditionally. It can also be used to find the Transitive Closure of a graph and detect negative-weight cycles in the graph.

To detect negative cycles using the Floyd–Warshall algorithm, check the distance matrix's diagonal for a negative number as it indicates that the graph contains at least one negative cycle.

How does this works?

The Floyd–Warshall algorithm iteratively revises path lengths between all pairs of vertices (i, j), including where i = j. Initially, the size of the path (i, i) is zero. A path [i, k…i] can only improve upon this if it has a length less than zero, i.e., denotes a negative cycle. Thus, after the algorithm, (i, i) will be negative if there exists a negative-length path from i back to i.

The algorithm can be implemented as follows in C++, Java, and Python:

C++


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

#include <iostream>

#include <vector>

#include <climits>

#include <iomanip>

using namespace std ;

// Recursive function to print path of given vertex `u` from source vertex `v`

void printPath ( vector < vector < int >> const &path , int v , int u )

{

if ( path [ v ] [ u ] == v ) {

return ;

}

printPath ( path , v , path [ v ] [ u ] ) ;

cout << path [ v ] [ u ] << ", " ;

}

// Function to print the shortest cost with path information between

// all pairs of vertices

void printSolution ( vector < vector < int >> const &cost , vector < vector < int >> const &path )

{

int n = cost . size ( ) ;

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

if ( u != v && path [ v ] [ u ] != - 1 )

{

cout << "The shortest path from " << v << " —> " << u << " is ["

<< v << ", " ;

printPath ( path , v , u ) ;

cout << u << "]" << endl ;

}

}

}

}

// Function to run the Floyd–Warshall algorithm

void floydWarshall ( vector < vector < int >> const &adjMatrix )

{

// total number of vertices in the `adjMatrix`

int n = adjMatrix . size ( ) ;

// base case

if ( n == 0 ) {

return ;

}

// cost[] and path[] stores shortest path

// (shortest cost/shortest route) information

vector < vector < int >> cost ( n , vector < int > ( n ) ) ;

vector < vector < int >> path ( n , vector < int > ( n ) ) ;

// initialize cost[] and path[]

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

// initially, cost would be the same as the weight of the edge

cost [ v ] [ u ] = adjMatrix [ v ] [ u ] ;

if ( v == u ) {

path [ v ] [ u ] = 0 ;

}

else if ( cost [ v ] [ u ] != INT_MAX ) {

path [ v ] [ u ] = v ;

}

else {

path [ v ] [ u ] = - 1 ;

}

}

}

// run Floyd–Warshall

for ( int k = 0 ; k < n ; k ++ )

{

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

// If vertex `k` is on the shortest path from `v` to `u`,

// then update the value of cost[v][u] and path[v][u]

if ( cost [ v ] [ k ] != INT_MAX && cost [ k ] [ u ] != INT_MAX

&& cost [ v ] [ k ] + cost [ k ] [ u ] < cost [ v ] [ u ] )

{

cost [ v ] [ u ] = cost [ v ] [ k ] + cost [ k ] [ u ] ;

path [ v ] [ u ] = path [ k ] [ u ] ;

}

}

// if diagonal elements become negative, the

// graph contains a negative-weight cycle

if ( cost [ v ] [ v ] < 0 )

{

cout << "Negative-weight cycle found!!" ;

return ;

}

}

}

// Print the shortest path between all pairs of vertices

printSolution ( cost , path ) ;

}

int main ( )

{

// define infinity

int I = INT_MAX ;

// given adjacency representation of the matrix

vector < vector < int >> adjMatrix =

{

{ 0 , I , - 2 , I } ,

{ 4 , 0 , 3 , I } ,

{ I , I , 0 , 2 } ,

{ I , - 1 , I , 0 }

} ;

// Run Floyd–Warshall algorithm

floydWarshall ( adjMatrix ) ;

return 0 ;

}

Download  Run Code

Java


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

import java . util . ArrayList ;

import java . util . List ;

class Main

{

// Recursive function to print path of given vertex `u` from source vertex `v`

private static void printPath ( int [ ] [ ] path , int v , int u , List <Integer> route )

{

if ( path [ v ] [ u ] == v ) {

return ;

}

printPath ( path , v , path [ v ] [ u ] , route ) ;

route . add ( path [ v ] [ u ] ) ;

}

// Function to print the shortest cost with path information between

// all pairs of vertices

private static void printSolution ( int [ ] [ ] path , int n )

{

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

if ( u != v && path [ v ] [ u ] != - 1 )

{

List <Integer> route = new ArrayList <> ( ) ;

route . add ( v ) ;

printPath ( path , v , u , route ) ;

route . add ( u ) ;

System . out . printf ( "The shortest path from %d —> %d is %s\n" ,

v , u , route ) ;

}

}

}

}

// Function to run the Floyd–Warshall algorithm

public static void floydWarshall ( int [ ] [ ] adjMatrix )

{

// base case

if ( adjMatrix == null || adjMatrix . length == 0 ) {

return ;

}

// total number of vertices in the `adjMatrix`

int n = adjMatrix . length ;

// cost[] and path[] stores shortest path

// (shortest cost/shortest route) information

int [ ] [ ] cost = new int [ n ] [ n ] ;

int [ ] [ ] path = new int [ n ] [ n ] ;

// initialize cost[] and path[]

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

// initially, cost would be the same as the weight of the edge

cost [ v ] [ u ] = adjMatrix [ v ] [ u ] ;

if ( v == u ) {

path [ v ] [ u ] = 0 ;

}

else if ( cost [ v ] [ u ] != Integer . MAX_VALUE ) {

path [ v ] [ u ] = v ;

}

else {

path [ v ] [ u ] = - 1 ;

}

}

}

// run Floyd–Warshall

for ( int k = 0 ; k < n ; k ++ )

{

for ( int v = 0 ; v < n ; v ++ )

{

for ( int u = 0 ; u < n ; u ++ )

{

// If vertex `k` is on the shortest path from `v` to `u`,

// then update the value of cost[v][u] and path[v][u]

if ( cost [ v ] [ k ] != Integer . MAX_VALUE

&& cost [ k ] [ u ] != Integer . MAX_VALUE

&& ( cost [ v ] [ k ] + cost [ k ] [ u ] < cost [ v ] [ u ] ) )

{

cost [ v ] [ u ] = cost [ v ] [ k ] + cost [ k ] [ u ] ;

path [ v ] [ u ] = path [ k ] [ u ] ;

}

}

// if diagonal elements become negative, the

// graph contains a negative-weight cycle

if ( cost [ v ] [ v ] < 0 )

{

System . out . println ( "Negative-weight cycle found!!" ) ;

return ;

}

}

}

// Print the shortest path between all pairs of vertices

printSolution ( path , n ) ;

}

public static void main ( String [ ] args )

{

// define infinity

int I = Integer . MAX_VALUE ;

// given adjacency representation of the matrix

int [ ] [ ] adjMatrix = new int [ ] [ ]

{

{ 0 , I , - 2 , I } ,

{ 4 , 0 , 3 , I } ,

{ I , I , 0 , 2 } ,

{ I , - 1 , I , 0 }

} ;

// Run Floyd–Warshall algorithm

floydWarshall ( adjMatrix ) ;

}

}

Download  Run Code

Python


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

# Recursive function to print the path of given vertex `u` from source vertex `v`

def printPath ( path , v , u , route ) :

if path [ v ] [ u ] == v :

return

printPath ( path , v , path [ v ] [ u ] , route )

route . append ( path [ v ] [ u ] )

# Function to print the shortest cost with path

# information between all pairs of vertices

def printSolution ( path , n ) :

for v in range ( n ) :

for u in range ( n ) :

if u != v and path [ v ] [ u ] != - 1 :

route = [ v ]

printPath ( path , v , u , route )

route . append ( u )

print ( f 'The shortest path from {v} —> {u} is' , route )

# Function to run the Floyd–Warshall algorithm

def floydWarshall ( adjMatrix ) :

# base case

if not adjMatrix :

return

# total number of vertices in the `adjMatrix`

n = len ( adjMatrix )

# cost and path matrix stores shortest path

# (shortest cost/shortest route) information

# initially, cost would be the same as the weight of an edge

cost = adjMatrix . copy ( )

path = [ [ None for x in range ( n ) ] for y in range ( n ) ]

# initialize cost and path

for v in range ( n ) :

for u in range ( n ) :

if v == u :

path [ v ] [ u ] = 0

elif cost [ v ] [ u ] != float ( 'inf' ) :

path [ v ] [ u ] = v

else :

path [ v ] [ u ] = - 1

# run Floyd–Warshall

for k in range ( n ) :

for v in range ( n ) :

for u in range ( n ) :

# If vertex `k` is on the shortest path from `v` to `u`,

# then update the value of cost[v][u] and path[v][u]

if cost [ v ] [ k ] != float ( 'inf' ) and cost [ k ] [ u ] != float ( 'inf' ) \

and ( cost [ v ] [ k ] + cost [ k ] [ u ] < cost [ v ] [ u ] ) :

cost [ v ] [ u ] = cost [ v ] [ k ] + cost [ k ] [ u ]

path [ v ] [ u ] = path [ k ] [ u ]

# if diagonal elements become negative, the

# graph contains a negative-weight cycle

if cost [ v ] [ v ] < 0 :

print ( 'Negative-weight cycle found' )

return

# Print the shortest path between all pairs of vertices

printSolution ( path , n )

if __name__ == '__main__' :

# define infinity

I = float ( 'inf' )

# given adjacency representation of the matrix

adjMatrix = [

[ 0 , I , - 2 , I ] ,

[ 4 , 0 , 3 , I ] ,

[ I , I , 0 , 2 ] ,

[ I , - 1 , I , 0 ]

]

# Run Floyd–Warshall algorithm

floydWarshall ( adjMatrix )

Download  Run Code

Output:

The shortest path from 0 —> 1 is [0, 2, 3, 1]
The shortest path from 0 —> 2 is [0, 2]
The shortest path from 0 —> 3 is [0, 2, 3]
The shortest path from 1 —> 0 is [1, 0]
The shortest path from 1 —> 2 is [1, 0, 2]
The shortest path from 1 —> 3 is [1, 0, 2, 3]
The shortest path from 2 —> 0 is [2, 3, 1, 0]
The shortest path from 2 —> 1 is [2, 3, 1]
The shortest path from 2 —> 3 is [2, 3]
The shortest path from 3 —> 0 is [3, 1, 0]
The shortest path from 3 —> 1 is [3, 1]
The shortest path from 3 —> 2 is [3, 1, 0, 2]

The time complexity of the Floyd–Warshall algorithm is O(V3), where V is the total number of vertices in the graph.


Johnson's algorithm can also be used to find the shortest paths between all pairs of vertices in a sparse, weighted, directed graph. It allows some edge weights to be negative numbers, but no negative-weight cycles may exist. It uses the Bellman–Ford algorithm to transform the input graph such that it removes all negative weights from the graph and run Dijkstra's algorithm on the transformed graph.


References:

https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
MIT: Shortest Paths III: All-pairs Shortest Paths, Matrix Multiplication, Floyd–Warshall, Johnson

All Pair Shortest Path Algorithm Using Dynamic Programming Example

Source: https://www.techiedelight.com/pairs-shortest-paths-floyd-warshall-algorithm/

0 Response to "All Pair Shortest Path Algorithm Using Dynamic Programming Example"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel