\chapter{Shortest paths} \index{shortest path} Finding the shortest path between two nodes is an important graph problem that has many applications in practice. For example, a natural problem in a road network is to calculate the length of the shorthest route between two cities, given the lengths of the roads. In an unweighted graph, the length of a path equals the number of edges in the path and we can simply use breadth-first search for finding the shortest path. However, in this chapter we concentrate on weighted graphs. In this case we need more sophisticated algorithms for finding shortest paths. \section{Bellman–Ford algorithm} \index{Bellman–Ford algorithm} The \key{Bellman–Fordin algoritmi} finds the shortest path from a starting node to all other nodes in the graph. The algorithm works in all kinds of graphs, provided that the graph doesn't contain a cycle with negative length. If the graph contains a negative cycle, the algorithm can detect this. The algorithm keeps track of estimated distances from the starting node to other nodes. Initially, the estimated distance is 0 to the starting node and infinite to all other nodes. The algorithm improves the estimates by finding edges that shorten the paths until it is not possible to improve any estimate. \subsubsection{Example} Let's consider how the Bellman–Ford algorithm works in the following graph: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (2) at (4,3) {2}; \node[draw, circle] (3) at (1,1) {3}; \node[draw, circle] (4) at (4,1) {4}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.55) {$0$}; \node[color=red] at (4,3+0.55) {$\infty$}; \node[color=red] at (1,1-0.55) {$\infty$}; \node[color=red] at (4,1-0.55) {$\infty$}; \node[color=red] at (6,2-0.55) {$\infty$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:3] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-2$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:3] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:5] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:2] {} (5); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \end{tikzpicture} \end{center} Each node in the graph is assigned an estimated distance. Initially, the distance is 0 to the starting node and infinite to all other nodes. The algorithm searches for edges that improve the estimated distances. First, all edges from node 1 improve the estimates: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (2) at (4,3) {2}; \node[draw, circle] (3) at (1,1) {3}; \node[draw, circle] (4) at (4,1) {4}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.55) {$0$}; \node[color=red] at (4,3+0.55) {$2$}; \node[color=red] at (1,1-0.55) {$3$}; \node[color=red] at (4,1-0.55) {$7$}; \node[color=red] at (6,2-0.55) {$\infty$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:3] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-2$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:3] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:5] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:2] {} (5); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \path[draw=red,thick,->,line width=2pt] (1) -- (2); \path[draw=red,thick,->,line width=2pt] (1) -- (3); \path[draw=red,thick,->,line width=2pt] (1) -- (4); \end{tikzpicture} \end{center} After this, edges $2 \rightarrow 5$ and $3 \rightarrow 4$ improve the estimates: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (2) at (4,3) {2}; \node[draw, circle] (3) at (1,1) {3}; \node[draw, circle] (4) at (4,1) {4}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.55) {$0$}; \node[color=red] at (4,3+0.55) {$2$}; \node[color=red] at (1,1-0.55) {$3$}; \node[color=red] at (4,1-0.55) {$1$}; \node[color=red] at (6,2-0.55) {$7$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:3] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-2$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:3] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:5] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:2] {} (5); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \path[draw=red,thick,->,line width=2pt] (2) -- (5); \path[draw=red,thick,->,line width=2pt] (3) -- (4); \end{tikzpicture} \end{center} Finally, there is one more improvment: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (2) at (4,3) {2}; \node[draw, circle] (3) at (1,1) {3}; \node[draw, circle] (4) at (4,1) {4}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.55) {$0$}; \node[color=red] at (4,3+0.55) {$2$}; \node[color=red] at (1,1-0.55) {$3$}; \node[color=red] at (4,1-0.55) {$1$}; \node[color=red] at (6,2-0.55) {$3$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:3] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-2$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:3] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:5] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:2] {} (5); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \path[draw=red,thick,->,line width=2pt] (4) -- (5); \end{tikzpicture} \end{center} After this, no edge improves the estimates. This means that the distances are final and we have successfully calculated the shortest distance from the starting node to all other nodes. For example, the smallest distance 3 from node 1 to node 5 corresponds to the following path: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (2) at (4,3) {2}; \node[draw, circle] (3) at (1,1) {3}; \node[draw, circle] (4) at (4,1) {4}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.55) {$0$}; \node[color=red] at (4,3+0.55) {$2$}; \node[color=red] at (1,1-0.55) {$3$}; \node[color=red] at (4,1-0.55) {$1$}; \node[color=red] at (6,2-0.55) {$3$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:3] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-2$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:3] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:5] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:2] {} (5); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \path[draw=red,thick,->,line width=2pt] (1) -- (3); \path[draw=red,thick,->,line width=2pt] (3) -- (4); \path[draw=red,thick,->,line width=2pt] (4) -- (5); \end{tikzpicture} \end{center} \subsubsection{Implementation} The following implementation of the Bellman–Ford algorithm finds the shortest paths from a node $x$ to all other nodes in the graph. The code assumes that the graph is stored as adjacency lists in array \begin{lstlisting} vector> v[N]; \end{lstlisting} so that each pair contains the target node and the edge weight. The algorithm consists of $n-1$ rounds, and on each round the algorithm goes through all nodes in the graph and tries to improve the estimated distances. The algorithm builds an array \texttt{e} that will contain the distance from $x$ to all nodes in the graph. The initial value $10^9$ means infinity. \begin{lstlisting} for (int i = 1; i <= n; i++) e[i] = 1e9; e[x] = 0; for (int i = 1; i <= n-1; i++) { for (int a = 1; a <= n; a++) { for (auto b : v[a]) { e[b.first] = min(e[b.first],e[a]+b.second); } } } \end{lstlisting} The time complexity of the algorithm is $O(nm)$ because it consists of $n-1$ rounds and iterates through all $m$ nodes during a round. If there are no negative cycles in the graph, all distances are final after $n-1$ rounds because each shortest path can contain at most $n-1$ edges. In practice, the final distances can usually be found much faster than in $n-1$ rounds. Thus, a possible way to make the algorithm more efficient is to stop the algorithm if we can't improve any distance during a round. \subsubsection{Negative cycle} \index{negative cycle} Using the Bellman–Ford algorithm we can also check if the graph contains a cycle with negative length. For example, the graph \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (0,0) {$1$}; \node[draw, circle] (2) at (2,1) {$2$}; \node[draw, circle] (3) at (2,-1) {$3$}; \node[draw, circle] (4) at (4,0) {$4$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:$3$] {} (2); \path[draw,thick,-] (2) -- node[font=\small,label=above:$1$] {} (4); \path[draw,thick,-] (1) -- node[font=\small,label=below:$5$] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-7$] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=right:$2$] {} (3); \end{tikzpicture} \end{center} \noindent contains a negative cycle $2 \rightarrow 3 \rightarrow 4 \rightarrow 2$ with length $-4$. If the graph contains a negative cycle, we can shorten a path that contains the cycle infinitely many times by repeating the cycle again and again. Thus, the concept of a shortest path is not meaningful here. A negative cycle can be detected using the Bellman–Ford algorithm by running the algorithm for $n$ rounds. If the last round improves any distance, the graph contains a negative cycle. Note that this algorithm searches for a negative cycle in the whole graph regardless of the starting node. \subsubsection{SPFA algorithm} \index{SPFA algorithm} The \key{SPFA algoritmi} (''Shortest Path Faster Algorithm'') is a variation for the Bellman–Ford algorithm, that is often more efficient than the original algorithm. It doesn't go through all the edges on each round, but instead, it chooses the edges to be examined in a more intelligent way. The algorithm maintains a queue of nodes that might be used for improving the distances. First, the algorithm adds the starting node $x$ to the queue. Then, the algorithm always processes the first node in the queue, and when an edge $a \rightarrow b$ improves a distance, node $b$ is added to the end of the queue. The following implementation uses a \texttt{queue} structure \texttt{q}. In addition, array \texttt{z} indicates if a node is already in the queue, in which case the algorithm doesn't add the node to the queue again. \begin{lstlisting} for (int i = 1; i <= n; i++) e[i] = 1e9; e[x] = 0; q.push(x); while (!q.empty()) { int a = q.front(); q.pop(); z[a] = 0; for (auto b : v[a]) { if (e[a]+b.second < e[b.first]) { e[b.first] = e[a]+b.second; if (!z[b]) {q.push(b); z[b] = 1;} } } } \end{lstlisting} The efficiency of the SPFA algorithm depends on the structure of the graph: the algorithm is usually very efficient, but its worst case time complexity is still $O(nm)$ and it is possible to create inputs that make the algorithm as slow as the standard Bellman–Ford algorithm. \section{Dijkstra's algorithm} \index{Dijkstra's algorithm} \key{Dijkstra's algorithm} finds the shortest paths from the starting node to all other nodes, like the Bellman–Ford algorithm. The benefit in Dijsktra's algorithm is that it is more efficient and can be used for processing large graphs. However, the algorithm requires that there are no negative weight edges in the graph. Like the Bellman–Ford algorithm, Dijkstra's algorithm maintains estimated distances for the nodes and improves them during the algorithm. Dijkstra's algorithm is efficient because it only processes each edge in the graph once, using the fact that there are no negative edges. \subsubsection{Example} Let's consider how Dijkstra's algorithm works in the following graph when the starting node is node 1: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (2) at (4,3) {4}; \node[draw, circle] (3) at (1,1) {2}; \node[draw, circle] (4) at (4,1) {1}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.6) {$\infty$}; \node[color=red] at (4,3+0.6) {$\infty$}; \node[color=red] at (1,1-0.6) {$\infty$}; \node[color=red] at (4,1-0.6) {$0$}; \node[color=red] at (6,2-0.6) {$\infty$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:6] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \end{tikzpicture} \end{center} Like in the Bellman–Ford algorithm, the estimated distance is 0 to the starting node and infinite to all other nodes. At each step, Dijkstra's algorithm selects a node that has not been processed yet and whose estimated distance is as small as possible. The first such node is node 1 with distance 0. When a node is selected, the algorithm goes through all edges that begin from the node and improves the distances using them: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (2) at (4,3) {4}; \node[draw, circle] (3) at (1,1) {2}; \node[draw, circle, fill=lightgray] (4) at (4,1) {1}; \node[draw, circle] (5) at (6,2) {5}; \node[color=red] at (1,3+0.6) {$\infty$}; \node[color=red] at (4,3+0.6) {$9$}; \node[color=red] at (1,1-0.6) {$5$}; \node[color=red] at (4,1-0.6) {$0$}; \node[color=red] at (6,2-0.6) {$1$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:6] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \path[draw=red,thick,->,line width=2pt] (4) -- (2); \path[draw=red,thick,->,line width=2pt] (4) -- (3); \path[draw=red,thick,->,line width=2pt] (4) -- (5); \end{tikzpicture} \end{center} The edges from node 1 improved distances to nodes 2, 4 and 5 whose now distances are now 5, 9 and 1. The next node to be processed is node 5 with distance 1: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (2) at (4,3) {4}; \node[draw, circle] (3) at (1,1) {2}; \node[draw, circle, fill=lightgray] (4) at (4,1) {1}; \node[draw, circle, fill=lightgray] (5) at (6,2) {5}; \node[color=red] at (1,3+0.6) {$\infty$}; \node[color=red] at (4,3+0.6) {$3$}; \node[color=red] at (1,1-0.6) {$5$}; \node[color=red] at (4,1-0.6) {$0$}; \node[color=red] at (6,2-0.6) {$1$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:6] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \path[draw=red,thick,->,line width=2pt] (5) -- (2); \end{tikzpicture} \end{center} After this, the next node is node 4: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {3}; \node[draw, circle, fill=lightgray] (2) at (4,3) {4}; \node[draw, circle] (3) at (1,1) {2}; \node[draw, circle, fill=lightgray] (4) at (4,1) {1}; \node[draw, circle, fill=lightgray] (5) at (6,2) {5}; \node[color=red] at (1,3+0.6) {$9$}; \node[color=red] at (4,3+0.6) {$3$}; \node[color=red] at (1,1-0.6) {$5$}; \node[color=red] at (4,1-0.6) {$0$}; \node[color=red] at (6,2-0.6) {$1$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:6] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \path[draw=red,thick,->,line width=2pt] (2) -- (1); \end{tikzpicture} \end{center} A nice property in Dijkstra's algorithm is that whenever a node is selected, its distance is final. For example, at this point of the algorithm, the distances 0, 1 and 3 are the final distances to nodes 1, 5 and 4. After this, the algorithm processes the two remaining nodes, and the final distances are as follows: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle, fill=lightgray] (1) at (1,3) {3}; \node[draw, circle, fill=lightgray] (2) at (4,3) {4}; \node[draw, circle, fill=lightgray] (3) at (1,1) {2}; \node[draw, circle, fill=lightgray] (4) at (4,1) {1}; \node[draw, circle, fill=lightgray] (5) at (6,2) {5}; \node[color=red] at (1,3+0.6) {$7$}; \node[color=red] at (4,3+0.6) {$3$}; \node[color=red] at (1,1-0.6) {$5$}; \node[color=red] at (4,1-0.6) {$0$}; \node[color=red] at (6,2-0.6) {$1$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:6] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \end{tikzpicture} \end{center} \subsubsection{Negative edges} The efficiency of Dijkstra's algorithm is based on the fact that the graph doesn't contain negative edges. If there is a negative edge, the algorithm may give incorrect results. As an example, consider the following graph: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (0,0) {$1$}; \node[draw, circle] (2) at (2,1) {$2$}; \node[draw, circle] (3) at (2,-1) {$3$}; \node[draw, circle] (4) at (4,0) {$4$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:2] {} (2); \path[draw,thick,-] (2) -- node[font=\small,label=above:3] {} (4); \path[draw,thick,-] (1) -- node[font=\small,label=below:6] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:$-5$] {} (4); \end{tikzpicture} \end{center} \noindent The shortest path from node 1 to node 4 is $1 \rightarrow 3 \rightarrow 4$, and its length is 1. However, Dijkstra's algorithm finds the path $1 \rightarrow 2 \rightarrow 4$ by following the lightest edges. The algorithm cannot recognize that in the lower path, the weight $-5$ compensates the previous large weight $6$. \subsubsection{Implementation} The following implementation of Dijkstra's algorithm calculates the minimum distance from a node $x$ to all other nodes. The graph is stored in an array \texttt{v} as adjacency lists that contain target nodes and weights for each edge. An efficient implementation of Dijkstra's algorithm requires that it is possible to quickly find the smallest node that has not been processed. A suitable data structure for this is a priority queue that contains the nodes ordered by the estimated distances. Using a priority queue, the next node to be processed can be retrieved in logarithmic time. In the following implementation, the priority queue contains pairs whose first element is the estimated distance and second element is the identifier of the corresponding node. \begin{lstlisting} priority_queue> q; \end{lstlisting} A small difficulty is that in Dijkstra's algorithm, we should find the node with \emph{minimum} distance, while the C++ priority queue finds the \emph{maximum} element as default. An easy solution is to use \emph{negative} distances, so we can directly use the C++ priority queue. The code keeps track of processed nodes in array \texttt{z}, and maintains estimated distances in array \texttt{e}. Initially, the distance to the starting node is 0, and the distance to all other nodes is $10^9$ that corresponds to infinity. \begin{lstlisting} for (int i = 1; i <= n; i++) e[i] = 1e9; e[x] = 0; q.push({0,x}); while (!q.empty()) { int a = q.top().second; q.pop(); if (z[a]) continue; z[a] = 1; for (auto b : v[a]) { if (e[a]+b.second < e[b]) { e[b] = e[a]+b.second; q.push({-e[b],b}); } } } \end{lstlisting} The time complexity of the above implementation is $O(n+m \log m)$ because the algorithm goes through all nodes in the graph, and adds for each edge at most one estimated distance to the priority queue. \section{Floyd–Warshall algorithm} \index{Floyd–Warshall algorithm} The \key{Floyd–Warshall algorithm} is an alternative way to approach the problem of finding shortest paths. Unlike other algorihms in this chapter, it finds all shortest paths between the nodes in a single run. The algorithm maintains a two-dimensional array that contains distances between the nodes. First, the distances are calculated only using direct edges between the nodes. After this the algorithm updates the distances by allowing to use intermediate nodes in the paths. \subsubsection{Example} Let's consider how the Floyd–Warshall algorithm works in the following graph: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {$3$}; \node[draw, circle] (2) at (4,3) {$4$}; \node[draw, circle] (3) at (1,1) {$2$}; \node[draw, circle] (4) at (4,1) {$1$}; \node[draw, circle] (5) at (6,2) {$5$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \end{tikzpicture} \end{center} Initially, the distance from each node to itself is $0$, and the distance between nodes $a$ and $b$ is $x$ if there is an edge between nodes $a$ and $b$ with weight $x$. All other distances are infinite. In this graph, the initial array is as follows: \begin{center} \begin{tabular}{r|rrrrr} & 1 & 2 & 3 & 4 & 5 \\ \hline 1 & 0 & 5 & $\infty$ & 9 & 1 \\ 2 & 5 & 0 & 2 & $\infty$ & $\infty$ \\ 3 & $\infty$ & 2 & 0 & 7 & $\infty$ \\ 4 & 9 & $\infty$ & 7 & 0 & 2 \\ 5 & 1 & $\infty$ & $\infty$ & 2 & 0 \\ \end{tabular} \end{center} \vspace{10pt} The algorithm consists of successive rounds. On each round, one new node is selected that can act as intermediate node in paths, and the algorithm improves the distances in the array using this node. On the first round, node 1 is the intermediate node. Now there is a new path between nodes 2 and 4 with length 14 because node 1 connects them. Correspondingly, there is a new path between nodes 2 and 5 with length 6. \begin{center} \begin{tabular}{r|rrrrr} & 1 & 2 & 3 & 4 & 5 \\ \hline 1 & 0 & 5 & $\infty$ & 9 & 1 \\ 2 & 5 & 0 & 2 & \textbf{14} & \textbf{6} \\ 3 & $\infty$ & 2 & 0 & 7 & $\infty$ \\ 4 & 9 & \textbf{14} & 7 & 0 & 2 \\ 5 & 1 & \textbf{6} & $\infty$ & 2 & 0 \\ \end{tabular} \end{center} \vspace{10pt} On the second round, node 2 is the intermediate node. This creates new paths between nodes 1 and 3, and between nodes 3 and 5: \begin{center} \begin{tabular}{r|rrrrr} & 1 & 2 & 3 & 4 & 5 \\ \hline 1 & 0 & 5 & \textbf{7} & 9 & 1 \\ 2 & 5 & 0 & 2 & 14 & 6 \\ 3 & \textbf{7} & 2 & 0 & 7 & \textbf{8} \\ 4 & 9 & 14 & 7 & 0 & 2 \\ 5 & 1 & 6 & \textbf{8} & 2 & 0 \\ \end{tabular} \end{center} \vspace{10pt} On the third round, node 3 is the intermediate round. There is a new path between nodes 2 and 4: \begin{center} \begin{tabular}{r|rrrrr} & 1 & 2 & 3 & 4 & 5 \\ \hline 1 & 0 & 5 & 7 & 9 & 1 \\ 2 & 5 & 0 & 2 & \textbf{9} & 6 \\ 3 & 7 & 2 & 0 & 7 & 8 \\ 4 & 9 & \textbf{9} & 7 & 0 & 2 \\ 5 & 1 & 6 & 8 & 2 & 0 \\ \end{tabular} \end{center} \vspace{10pt} The algorithm continues like this, until all nodes have been intermediate nodes. After the algorithm has finished, the array contains the minimum distance between any two nodes: \begin{center} \begin{tabular}{r|rrrrr} & 1 & 2 & 3 & 4 & 5 \\ \hline 1 & 0 & 5 & 7 & 3 & 1 \\ 2 & 5 & 0 & 2 & 9 & 6 \\ 3 & 7 & 2 & 0 & 7 & 8 \\ 4 & 3 & 9 & 7 & 0 & 2 \\ 5 & 1 & 6 & 8 & 2 & 0 \\ \end{tabular} \end{center} For example, the array indicates that the shortest path between nodes 2 and 4 has length 8. This corresponds to the following path: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {$3$}; \node[draw, circle] (2) at (4,3) {$4$}; \node[draw, circle] (3) at (1,1) {$2$}; \node[draw, circle] (4) at (4,1) {$1$}; \node[draw, circle] (5) at (6,2) {$5$}; \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (2); \path[draw,thick,-] (1) -- node[font=\small,label=left:2] {} (3); \path[draw,thick,-] (3) -- node[font=\small,label=below:5] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=left:9] {} (4); \path[draw,thick,-] (2) -- node[font=\small,label=above:2] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \path[draw=red,thick,->,line width=2pt] (3) -- (4); \path[draw=red,thick,->,line width=2pt] (4) -- (5); \path[draw=red,thick,->,line width=2pt] (5) -- (2); \end{tikzpicture} \end{center} \subsubsection{Implementation} The benefit in the Floyd–Warshall algorithm that it is easy to implement. The following code constructs a distance matrix \texttt{d} where $\texttt{d}[a][b]$ is the smallest distance in a path between nodes $a$ and $b$. First, the algorithm initializes \texttt{d} using the adjacency matrix \texttt{v} of the graph (value $10^9$ means infinity): \begin{lstlisting} for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (i == j) d[i][j] = 0; else if (v[i][j]) d[i][j] = v[i][j]; else d[i][j] = 1e9; } } \end{lstlisting} After this, the shortest paths can be found as follows: \begin{lstlisting} for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { d[i][j] = min(d[i][j], d[i][k]+d[k][j]); } } } \end{lstlisting} The time complexity of the algorithm is $O(n^3)$ because it contains three nested loops that go through the nodes in the graph. Since the implementation of the Floyd–Warshall algorithm is simple, the algorithm can be a good choice even if we need to find only a single shortest path in the graph. However, this is only possible when the graph is so small that a cubic time complexity is enough.