Corrections

This commit is contained in:
Antti H S Laaksonen 2017-02-05 11:51:38 +02:00
parent c9460ad2d3
commit 0d71484380
1 changed files with 96 additions and 96 deletions

View File

@ -3,7 +3,8 @@
\index{shortest path} \index{shortest path}
Finding the shortest path between two nodes Finding the shortest path between two nodes
is an important graph problem that has many of a graph
is an important problem that has many
applications in practice. applications in practice.
For example, a natural problem in a road network For example, a natural problem in a road network
is to calculate the length of the shorthest route is to calculate the length of the shorthest route
@ -11,37 +12,38 @@ between two cities, given the lengths of the roads.
In an unweighted graph, the length of a path equals In an unweighted graph, the length of a path equals
the number of edges in the path and we can the number of edges in the path and we can
simply use breadth-first search for finding simply use breadth-first search to find
the shortest path. the shortest path.
However, in this chapter we concentrate on However, in this chapter we concentrate on
weighted graphs. weighted graphs,
In this case we need more sophisticated algorithms and more sophisticated algorithms
are needed
for finding shortest paths. for finding shortest paths.
\section{BellmanFord algorithm} \section{BellmanFord algorithm}
\index{BellmanFord algorithm} \index{BellmanFord algorithm}
The \key{BellmanFordin algoritmi} finds the The \key{BellmanFord algorithm} finds the
shortest path from a starting node to all shortest paths from a starting node to all
other nodes in the graph. other nodes in the graph.
The algorithm works in all kinds of graphs, The algorithm can process all kinds of graphs,
provided that the graph doesn't contain a provided that the graph does not contain a
cycle with negative length. cycle with negative length.
If the graph contains a negative cycle, If the graph contains a negative cycle,
the algorithm can detect this. the algorithm can detect this.
The algorithm keeps track of estimated distances The algorithm keeps track of distances
from the starting node to other nodes. from the starting node to other nodes.
Initially, the estimated distance is 0 Initially, the distance to the starting node is 0
to the starting node and infinite to all other nodes. and the distance to all other nodes in infinite.
The algorithm improves the estimates by finding The algorithm reduces the distances by finding
edges that shorten the paths until it is not edges that shorten the paths until it is not
possible to improve any estimate. possible to reduce any distance.
\subsubsection{Example} \subsubsection{Example}
Let's consider how the BellmanFord algorithm Let us consider how the BellmanFord algorithm
works in the following graph: works in the following graph:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
@ -64,13 +66,13 @@ works in the following graph:
\path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4); \path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Each node in the graph is assigned an estimated distance. Each node in the graph is assigned a distance.
Initially, the distance is 0 to the starting node Initially, the distance to the starting node is 0,
and infinite to all other nodes. and the distance to all other nodes is infinite.
The algorithm searches for edges that improve the The algorithm searches for edges that reduce the
estimated distances. distances.
First, all edges from node 1 improve the estimates: First, all edges from node 1 reduce the distances:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (1) at (1,3) {1};
@ -98,7 +100,7 @@ First, all edges from node 1 improve the estimates:
\end{center} \end{center}
After this, edges After this, edges
$2 \rightarrow 5$ and $3 \rightarrow 4$ $2 \rightarrow 5$ and $3 \rightarrow 4$
improve the estimates: reduce the distances:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (1) at (1,3) {1};
@ -123,7 +125,7 @@ improve the estimates:
\path[draw=red,thick,->,line width=2pt] (3) -- (4); \path[draw=red,thick,->,line width=2pt] (3) -- (4);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Finally, there is one more improvment: Finally, there is one more change:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (1,3) {1}; \node[draw, circle] (1) at (1,3) {1};
@ -148,7 +150,7 @@ Finally, there is one more improvment:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
After this, no edge improves the estimates. After this, no edge can reduce any distance.
This means that the distances are final This means that the distances are final
and we have successfully and we have successfully
calculated the shortest distance calculated the shortest distance
@ -187,20 +189,20 @@ the following path:
\subsubsection{Implementation} \subsubsection{Implementation}
The following implementation of the The following implementation of the
BellmanFord algorithm finds the shortest paths BellmanFord algorithm finds the shortest distances
from a node $x$ to all other nodes in the graph. from a node $x$ to all other nodes in the graph.
The code assumes that the graph is stored The code assumes that the graph is stored
as adjacency lists in array as adjacency lists in an array
\begin{lstlisting} \begin{lstlisting}
vector<pair<int,int>> v[N]; vector<pair<int,int>> v[N];
\end{lstlisting} \end{lstlisting}
so that each pair contains the target node as pairs of the form $(x,w)$:
and the edge weight. there is an edge to node $x$ with weight $w$.
The algorithm consists of $n-1$ rounds, The algorithm consists of $n-1$ rounds,
and on each round the algorithm goes through and on each round the algorithm goes through
all nodes in the graph and tries to improve all edges in the graph and tries to
the estimated distances. reduce the distances.
The algorithm builds an array \texttt{e} The algorithm builds an array \texttt{e}
that will contain the distance from $x$ that will contain the distance from $x$
to all nodes in the graph. to all nodes in the graph.
@ -218,24 +220,24 @@ for (int i = 1; i <= n-1; i++) {
} }
\end{lstlisting} \end{lstlisting}
The time complexity of the algorithm is $O(nm)$ The time complexity of the algorithm is $O(nm)$,
because it consists of $n-1$ rounds and because the algorithm consists of $n-1$ rounds and
iterates through all $m$ nodes during a round. iterates through all $m$ edges during a round.
If there are no negative cycles in the graph, If there are no negative cycles in the graph,
all distances are final after $n-1$ rounds all distances are final after $n-1$ rounds,
because each shortest path can contain at most $n-1$ edges. because each shortest path can contain at most $n-1$ edges.
In practice, the final distances can usually In practice, the final distances can usually
be found much faster than in $n-1$ rounds. be found much faster than in $n-1$ rounds.
Thus, a possible way to make the algorithm more efficient Thus, a possible way to make the algorithm more efficient
is to stop the algorithm if we can't is to stop the algorithm if no distance
improve any distance during a round. can be reduced during a round.
\subsubsection{Negative cycle} \subsubsection{Negative cycle}
\index{negative cycle} \index{negative cycle}
Using the BellmanFord algorithm we can also The BellmanFord algorithm can be also used to
check if the graph contains a cycle with negative length. check if the graph contains a cycle with negative length.
For example, the graph For example, the graph
@ -263,12 +265,12 @@ we can shorten a path that contains the cycle
infinitely many times by repeating the cycle infinitely many times by repeating the cycle
again and again. again and again.
Thus, the concept of a shortest path Thus, the concept of a shortest path
is not meaningful here. is not meaningful in this situation.
A negative cycle can be detected A negative cycle can be detected
using the BellmanFord algorithm by using the BellmanFord algorithm by
running the algorithm for $n$ rounds. running the algorithm for $n$ rounds.
If the last round improves any distance, If the last round reduces any distance,
the graph contains a negative cycle. the graph contains a negative cycle.
Note that this algorithm searches for Note that this algorithm searches for
a negative cycle in the whole graph a negative cycle in the whole graph
@ -278,27 +280,27 @@ regardless of the starting node.
\index{SPFA algorithm} \index{SPFA algorithm}
The \key{SPFA algoritmi} (''Shortest Path Faster Algorithm'') The \key{SPFA algorithm} (''Shortest Path Faster Algorithm'')
is a variation for the BellmanFord algorithm, is a variant of the BellmanFord algorithm,
that is often more efficient than the original algorithm. that is often more efficient than the original algorithm.
It doesn't go through all the edges on each round, It does not go through all the edges on each round,
but instead, it chooses the edges to be examined but instead, it chooses the edges to be examined
in a more intelligent way. in a more intelligent way.
The algorithm maintains a queue of nodes that might The algorithm maintains a queue of nodes that might
be used for improving the distances. be used for reducing the distances.
First, the algorithm adds the starting node $x$ First, the algorithm adds the starting node $x$
to the queue. to the queue.
Then, the algorithm always processes the Then, the algorithm always processes the
first node in the queue, and when an edge first node in the queue, and when an edge
$a \rightarrow b$ improves a distance, $a \rightarrow b$ reduces a distance,
node $b$ is added to the end of the queue. node $b$ is added to the end of the queue.
The following implementation uses a The following implementation uses a
\texttt{queue} structure \texttt{q}. \texttt{queue} structure \texttt{q}.
In addition, array \texttt{z} indicates In addition, the array \texttt{z} indicates
if a node is already in the queue, if a node is already in the queue,
in which case the algorithm doesn't add in which case the algorithm does not add
the node to the queue again. the node to the queue again.
\begin{lstlisting} \begin{lstlisting}
@ -319,7 +321,7 @@ while (!q.empty()) {
The efficiency of the SPFA algorithm depends The efficiency of the SPFA algorithm depends
on the structure of the graph: on the structure of the graph:
the algorithm is usually very efficient, the algorithm is often very efficient,
but its worst case time complexity is still but its worst case time complexity is still
$O(nm)$ and it is possible to create inputs $O(nm)$ and it is possible to create inputs
that make the algorithm as slow as the that make the algorithm as slow as the
@ -339,16 +341,16 @@ However, the algorithm requires that there
are no negative weight edges in the graph. are no negative weight edges in the graph.
Like the BellmanFord algorithm, Like the BellmanFord algorithm,
Dijkstra's algorithm maintains estimated distances Dijkstra's algorithm maintains distances
for the nodes and improves them during the algorithm. for the nodes and reduces them during the algorithm.
Dijkstra's algorithm is efficient because Dijkstra's algorithm is efficient, because
it only processes it only processes
each edge in the graph once, using the fact each edge in the graph once, using the fact
that there are no negative edges. that there are no negative edges.
\subsubsection{Example} \subsubsection{Example}
Let's consider how Dijkstra's algorithm Let us consider how Dijkstra's algorithm
works in the following graph when the works in the following graph when the
starting node is node 1: starting node is node 1:
\begin{center} \begin{center}
@ -374,17 +376,17 @@ starting node is node 1:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Like in the BellmanFord algorithm, Like in the BellmanFord algorithm,
the estimated distance is 0 to the starting node intially the distance to the starting node is 0
and infinite to all other nodes. and the distance to all other nodes is infinite.
At each step, Dijkstra's algorithm selects a node At each step, Dijkstra's algorithm selects a node
that has not been processed yet and whose estimated distance that has not been processed yet and whose distance
is as small as possible. is as small as possible.
The first such node is node 1 with distance 0. The first such node is node 1 with distance 0.
When a node is selected, the algorithm When a node is selected, the algorithm
goes through all edges that begin from the node goes through all edges that start at the node
and improves the distances using them: and reduces the distances using them:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (1) at (1,3) {3};
@ -411,8 +413,8 @@ and improves the distances using them:
\path[draw=red,thick,->,line width=2pt] (4) -- (5); \path[draw=red,thick,->,line width=2pt] (4) -- (5);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
The edges from node 1 improved distances to The edges from node 1 reduced distances to
nodes 2, 4 and 5 whose now distances are now 5, 9 and 1. nodes 2, 4 and 5, whose distances are now 5, 9 and 1.
The next node to be processed is node 5 with distance 1: The next node to be processed is node 5 with distance 1:
\begin{center} \begin{center}
@ -465,7 +467,7 @@ After this, the next node is node 4:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
A nice property in Dijkstra's algorithm is that A remarkable property in Dijkstra's algorithm is that
whenever a node is selected, its distance is final. whenever a node is selected, its distance is final.
For example, at this point of the algorithm, For example, at this point of the algorithm,
the distances 0, 1 and 3 are the final distances the distances 0, 1 and 3 are the final distances
@ -500,7 +502,7 @@ remaining nodes, and the final distances are as follows:
\subsubsection{Negative edges} \subsubsection{Negative edges}
The efficiency of Dijkstra's algorithm is The efficiency of Dijkstra's algorithm is
based on the fact that the graph doesn't based on the fact that the graph does not
contain negative edges. contain negative edges.
If there is a negative edge, If there is a negative edge,
the algorithm may give incorrect results. the algorithm may give incorrect results.
@ -521,52 +523,50 @@ As an example, consider the following graph:
\end{center} \end{center}
\noindent \noindent
The shortest path from node 1 to node 4 is The shortest path from node 1 to node 4 is
$1 \rightarrow 3 \rightarrow 4$, $1 \rightarrow 3 \rightarrow 4$
and its length is 1. and its length is 1.
However, Dijkstra's algorithm However, Dijkstra's algorithm
finds the path $1 \rightarrow 2 \rightarrow 4$ finds the path $1 \rightarrow 2 \rightarrow 4$
by following the lightest edges. by following the minimum weight edges.
The algorithm cannot recognize that The algorithm does not take into account that
in the lower path, the weight $-5$ on the lower path, the weight $-5$
compensates the previous large weight $6$. compensates the previous large weight $6$.
\subsubsection{Implementation} \subsubsection{Implementation}
The following implementation of Dijkstra's algorithm The following implementation of Dijkstra's algorithm
calculates the minimum distance from a node $x$ calculates the minimum distances from a node $x$
to all other nodes. to all other nodes.
The graph is stored in an array \texttt{v} The graph is stored in an array \texttt{v}
as adjacency lists that contain target nodes as adjacency lists like in the BellmanFord algorithm.
and weights for each edge.
An efficient implementation of Dijkstra's algorithm An efficient implementation of Dijkstra's algorithm
requires that it is possible to quickly find the requires that it is possible to efficiently find the
smallest node that has not been processed. minimum distance node that has not been processed.
A suitable data structure for this is a priority queue An appropriate data structure for this is a priority queue
that contains the nodes ordered by the estimated distances. that contains the nodes ordered by their distances.
Using a priority queue, the next node to be processed Using a priority queue, the next node to be processed
can be retrieved in logarithmic time. can be retrieved in logarithmic time.
In the following implementation, In the following implementation,
the priority queue contains pairs whose first the priority queue contains pairs whose first
element is the estimated distance and second element is the current distance of the node and second
element is the identifier of the corresponding node. element is the identifier of the node.
\begin{lstlisting} \begin{lstlisting}
priority_queue<pair<int,int>> q; priority_queue<pair<int,int>> q;
\end{lstlisting} \end{lstlisting}
A small difficulty is that in Dijkstra's algorithm, A small difficulty is that in Dijkstra's algorithm,
we should find the node with \emph{minimum} distance, we should find the node with the \emph{minimum} distance,
while the C++ priority queue finds the \emph{maximum} while the C++ priority queue finds the \emph{maximum}
element as default. element as default.
An easy solution is to use \emph{negative} distances, An easy solution is to use \emph{negative} distances,
so we can directly use the C++ priority queue. which allows us to directly use the C++ priority queue.
The code keeps track of processed nodes The code keeps track of processed nodes
in array \texttt{z}, in the array \texttt{z},
and maintains estimated distances in array \texttt{e}. and maintains estimated distances in array \texttt{e}.
Initially, the distance to the starting node is 0, Initially, the distance to the starting node is 0,
and the distance to all other nodes is $10^9$ and the distance to all other nodes is $10^9$ (infinite).
that corresponds to infinity.
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) e[i] = 1e9; for (int i = 1; i <= n; i++) e[i] = 1e9;
@ -597,7 +597,7 @@ at most one estimated distance to the priority queue.
The \key{FloydWarshall algorithm} The \key{FloydWarshall algorithm}
is an alternative way to approach the problem is an alternative way to approach the problem
of finding shortest paths. of finding shortest paths.
Unlike other algorihms in this chapter, Unlike the other algorihms in this chapter,
it finds all shortest paths between the nodes it finds all shortest paths between the nodes
in a single run. in a single run.
@ -606,11 +606,11 @@ that contains distances between the nodes.
First, the distances are calculated only using First, the distances are calculated only using
direct edges between the nodes. direct edges between the nodes.
After this the algorithm updates the distances After this the algorithm updates the distances
by allowing to use intermediate nodes in the paths. by using intermediate nodes in the paths.
\subsubsection{Example} \subsubsection{Example}
Let's consider how the FloydWarshall algorithm Let us consider how the FloydWarshall algorithm
works in the following graph: works in the following graph:
\begin{center} \begin{center}
@ -648,16 +648,16 @@ In this graph, the initial array is as follows:
\end{tabular} \end{tabular}
\end{center} \end{center}
\vspace{10pt} \vspace{10pt}
The algorithm consists of successive rounds. The algorithm consists of consecutive rounds.
On each round, one new node is selected that On each round, the algorithm selects a new node
can act as intermediate node in paths, that can act as an intermediate node in paths from now on,
and the algorithm improves the distances in the array and the algorithm reduces the distances in the array
using this node. using this node.
On the first round, node 1 is the intermediate node. On the first round, node 1 is the intermediate node.
Now there is a new path between nodes 2 and 4 There is a new path between nodes 2 and 4
with length 14 because node 1 connects them. with length 14, because node 1 connects them.
Correspondingly, there is a new path There is also a new path
between nodes 2 and 5 with length 6. between nodes 2 and 5 with length 6.
\begin{center} \begin{center}
@ -674,7 +674,7 @@ between nodes 2 and 5 with length 6.
\vspace{10pt} \vspace{10pt}
On the second round, node 2 is the intermediate node. On the second round, node 2 is the intermediate node.
This creates new paths between nodes 1 and 3, This creates new paths between nodes 1 and 3
and between nodes 3 and 5: and between nodes 3 and 5:
\begin{center} \begin{center}
@ -709,7 +709,7 @@ There is a new path between nodes 2 and 4:
The algorithm continues like this, The algorithm continues like this,
until all nodes have been intermediate nodes. until all nodes have been intermediate nodes.
After the algorithm has finished, the array contains After the algorithm has finished, the array contains
the minimum distance between any two nodes: the minimum distances between any two nodes:
\begin{center} \begin{center}
\begin{tabular}{r|rrrrr} \begin{tabular}{r|rrrrr}
@ -750,15 +750,15 @@ This corresponds to the following path:
\subsubsection{Implementation} \subsubsection{Implementation}
The benefit in the The advantage of the
FloydWarshall algorithm that it is FloydWarshall algorithm that it is
easy to implement. easy to implement.
The following code constructs a The following code constructs a
distance matrix \texttt{d} where $\texttt{d}[a][b]$ distance matrix \texttt{d} where $\texttt{d}[a][b]$
is the smallest distance in a path between nodes $a$ and $b$. is the smallest distance between nodes $a$ and $b$.
First, the algorithm initializes \texttt{d} First, the algorithm initializes \texttt{d}
using the adjacency matrix \texttt{v} of the graph using the adjacency matrix \texttt{v} of the graph
(value $10^9$ means infinity): ($10^9$ means infinity):
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
@ -782,13 +782,13 @@ for (int k = 1; k <= n; k++) {
} }
\end{lstlisting} \end{lstlisting}
The time complexity of the algorithm is $O(n^3)$ The time complexity of the algorithm is $O(n^3)$,
because it contains three nested loops because it contains three nested loops
that go through the nodes in the graph. that go through the nodes in the graph.
Since the implementation of the FloydWarshall Since the implementation of the FloydWarshall
algorithm is simple, the algorithm can be algorithm is simple, the algorithm can be
a good choice even if we need to find only a a good choice even if it is only needed to find a
single shortest path in the graph. single shortest path in the graph.
However, this is only possible when the graph However, the algorithm can only be used when the graph
is so small that a cubic time complexity is enough. is so small that a cubic time complexity is fast enough.