Corrections
This commit is contained in:
parent
f478d7044c
commit
c447a6f33b
127
luku11.tex
127
luku11.tex
|
@ -1,12 +1,12 @@
|
|||
\chapter{Basics of graphs}
|
||||
|
||||
Many programming problems can be solved by
|
||||
modelling the problem as a graph problem
|
||||
modeling the problem as a graph problem
|
||||
and using an appropriate graph algorithm.
|
||||
A typical example of a graph is a network
|
||||
of roads and cities in a country.
|
||||
Sometimes, though, the graph is hidden
|
||||
in the problem and it can be difficult to detect it.
|
||||
in the problem and it may be difficult to detect it.
|
||||
|
||||
This part of the book discusses graph algorithms,
|
||||
especially focusing on topics that
|
||||
|
@ -15,7 +15,7 @@ In this chapter, we go through concepts
|
|||
related to graphs,
|
||||
and study different ways to represent graphs in algorithms.
|
||||
|
||||
\section{Terminology}
|
||||
\section{Graph terminology}
|
||||
|
||||
\index{graph}
|
||||
\index{node}
|
||||
|
@ -56,17 +56,51 @@ A \key{path} leads from node $a$ to node $b$
|
|||
through edges of the graph.
|
||||
The \key{length} of a path is the number of
|
||||
edges in it.
|
||||
For example, in the above graph, there
|
||||
are several paths from node 1 to node 5:
|
||||
For example, the above graph contains
|
||||
the path $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$
|
||||
from node 1 to node 5:
|
||||
|
||||
\begin{itemize}
|
||||
\item $1 \rightarrow 2 \rightarrow 5$ (length 2)
|
||||
\item $1 \rightarrow 4 \rightarrow 5$ (length 2)
|
||||
\item $1 \rightarrow 2 \rightarrow 4 \rightarrow 5$ (length 3)
|
||||
\item $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ (length 3)
|
||||
\item $1 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 3)
|
||||
\item $1 \rightarrow 3 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 4)
|
||||
\end{itemize}
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
\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$};
|
||||
|
||||
\path[draw,thick,-] (1) -- (2);
|
||||
\path[draw,thick,-] (1) -- (3);
|
||||
\path[draw,thick,-] (1) -- (4);
|
||||
\path[draw,thick,-] (3) -- (4);
|
||||
\path[draw,thick,-] (2) -- (4);
|
||||
\path[draw,thick,-] (2) -- (5);
|
||||
\path[draw,thick,-] (4) -- (5);
|
||||
|
||||
\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}
|
||||
|
||||
\index{cycle}
|
||||
|
||||
A path is a \key{cycle} if the first and last
|
||||
node is the same.
|
||||
For example, the above graph contains
|
||||
the cycle $1 \rightarrow 3 \rightarrow 4 \rightarrow 1$.
|
||||
A path is \key{simple} if each node appears
|
||||
at most once in the path.
|
||||
|
||||
|
||||
%
|
||||
% \begin{itemize}
|
||||
% \item $1 \rightarrow 2 \rightarrow 5$ (length 2)
|
||||
% \item $1 \rightarrow 4 \rightarrow 5$ (length 2)
|
||||
% \item $1 \rightarrow 2 \rightarrow 4 \rightarrow 5$ (length 3)
|
||||
% \item $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ (length 3)
|
||||
% \item $1 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 3)
|
||||
% \item $1 \rightarrow 3 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 4)
|
||||
% \end{itemize}
|
||||
|
||||
\subsubsection{Connectivity}
|
||||
|
||||
|
@ -185,29 +219,18 @@ For example, the following graph is directed:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
The above graph contains a path from
|
||||
node $3$ to node $5$ through the edges
|
||||
$3 \rightarrow 1 \rightarrow 2 \rightarrow 5$,
|
||||
The above graph contains
|
||||
the path $3 \rightarrow 1 \rightarrow 2 \rightarrow 5$
|
||||
from node $3$ to node $5$,
|
||||
but there is no path from node $5$ to node $3$.
|
||||
|
||||
\index{cycle}
|
||||
\index{acyclic graph}
|
||||
|
||||
A \key{cycle} is a path whose first and
|
||||
last node is the same.
|
||||
For example, the above graph contains
|
||||
a cycle
|
||||
$1 \rightarrow 2 \rightarrow 4 \rightarrow 1$.
|
||||
If a graph does not contain any cycles,
|
||||
it is called \key{acyclic}.
|
||||
|
||||
\subsubsection{Edge weights}
|
||||
|
||||
\index{weighted graph}
|
||||
|
||||
In a \key{weighted} graph, each edge is assigned
|
||||
a \key{weight}.
|
||||
Often, the weights are interpreted as edge lengths.
|
||||
Often the weights are interpreted as edge lengths.
|
||||
For example, the following graph is weighted:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -268,7 +291,7 @@ so its degree is 3.
|
|||
The sum of degrees in a graph is always $2m$,
|
||||
where $m$ is the number of edges,
|
||||
because each edge
|
||||
increases the degree of two nodes by one.
|
||||
increases the degree of exactly two nodes by one.
|
||||
For this reason, the sum of degrees is always even.
|
||||
|
||||
\index{regular graph}
|
||||
|
@ -358,7 +381,7 @@ is bipartite, because it can be colored as follows:
|
|||
\path[draw,thick,-] (5) -- (6);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
However, the following graph is not bipartite:
|
||||
However, the graph
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
\node[draw, circle] (1) at (1,3) {$2$};
|
||||
|
@ -376,6 +399,29 @@ However, the following graph is not bipartite:
|
|||
\path[draw,thick,-] (1) -- (6);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
is not bipartite, because it is not possible to color
|
||||
the following cycle of three nodes using two colors:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
\node[draw, circle] (1) at (1,3) {$2$};
|
||||
\node[draw, circle] (2) at (4,3) {$3$};
|
||||
\node[draw, circle] (3) at (1,1) {$5$};
|
||||
\node[draw, circle] (4) at (4,1) {$6$};
|
||||
\node[draw, circle] (5) at (-2,1) {$4$};
|
||||
\node[draw, circle] (6) at (-2,3) {$1$};
|
||||
\path[draw,thick,-] (1) -- (2);
|
||||
\path[draw,thick,-] (1) -- (3);
|
||||
\path[draw,thick,-] (3) -- (4);
|
||||
\path[draw,thick,-] (2) -- (4);
|
||||
\path[draw,thick,-] (3) -- (6);
|
||||
\path[draw,thick,-] (5) -- (6);
|
||||
\path[draw,thick,-] (1) -- (6);
|
||||
|
||||
\path[draw=red,thick,-,line width=2pt] (1) -- (3);
|
||||
\path[draw=red,thick,-,line width=2pt] (3) -- (6);
|
||||
\path[draw=red,thick,-,line width=2pt] (6) -- (1);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
\subsubsection{Simplicity}
|
||||
|
||||
|
@ -386,7 +432,7 @@ if no edge starts and ends at the same node,
|
|||
and there are no multiple
|
||||
edges between two nodes.
|
||||
Often we assume that graphs are simple.
|
||||
For example, the graph
|
||||
For example, the following graph is \emph{not} simple:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
\node[draw, circle] (1) at (1,3) {$2$};
|
||||
|
@ -409,9 +455,6 @@ For example, the graph
|
|||
\path[draw,thick,-] (5) edge [loop left] (5);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
is \emph{not} simple, because there is an edge that starts
|
||||
and ends at node 4, and there are two edges
|
||||
between nodes 2 and 3.
|
||||
|
||||
\section{Graph representation}
|
||||
|
||||
|
@ -420,7 +463,7 @@ in algorithms.
|
|||
The choice of a data structure
|
||||
depends on the size of the graph and
|
||||
the way the algorithm processes it.
|
||||
Next we will go through three possible representations.
|
||||
Next we will go through three common representations.
|
||||
|
||||
\subsubsection{Adjacency list representation}
|
||||
|
||||
|
@ -431,7 +474,7 @@ each node $x$ in the graph is assigned an \key{adjacency list}
|
|||
that consists of nodes
|
||||
to which there is an edge from $x$.
|
||||
Adjacency lists are the most popular
|
||||
way to represent a graph, and most algorithms can be
|
||||
way to represent graphs, and most algorithms can be
|
||||
efficiently implemented using them.
|
||||
|
||||
A convenient way to store the adjacency lists is to declare
|
||||
|
@ -440,8 +483,8 @@ an array of vectors as follows:
|
|||
vector<int> v[N];
|
||||
\end{lstlisting}
|
||||
|
||||
The constant $N$ is chosen so that there
|
||||
is space for all adjacency lists.
|
||||
The constant $N$ is chosen so that all
|
||||
adjacency lists can be stored.
|
||||
For example, the graph
|
||||
|
||||
\begin{center}
|
||||
|
@ -468,7 +511,7 @@ v[4].push_back(1);
|
|||
\end{lstlisting}
|
||||
|
||||
If the graph is undirected, it can be stored in a similar way,
|
||||
but each edge is stored in both directions.
|
||||
but each edge is added in both directions.
|
||||
|
||||
For a weighted graph, the structure can be extended
|
||||
as follows:
|
||||
|
@ -507,7 +550,7 @@ v[4].push_back({1,2});
|
|||
|
||||
The benefit in using adjacency lists is that
|
||||
we can efficiently find the nodes to which
|
||||
we can move from a certain node through an edge.
|
||||
we can move from a given node through an edge.
|
||||
For example, the following loop goes through all nodes
|
||||
to which we can move from node $s$:
|
||||
|
||||
|
@ -522,7 +565,7 @@ for (auto u : v[s]) {
|
|||
\index{adjacency matrix}
|
||||
|
||||
An \key{adjacency matrix} is a two-dimensional array
|
||||
that indicates which edges exist in the graph.
|
||||
that indicates which edges the graph contains.
|
||||
We can efficiently check from an adjacency matrix
|
||||
if there is an edge between two nodes.
|
||||
The matrix can be stored as an array
|
||||
|
@ -647,7 +690,7 @@ if the graph is large.
|
|||
An \key{edge list} contains all edges of a graph
|
||||
in some order.
|
||||
This is a convenient way to represent a graph
|
||||
if the algorithm processes all edges of the graph,
|
||||
if the algorithm processes all edges of the graph
|
||||
and it is not needed to find edges that start
|
||||
at a given node.
|
||||
|
||||
|
|
40
luku12.tex
40
luku12.tex
|
@ -48,9 +48,8 @@ the following graph:
|
|||
\path[draw,thick,-] (2) -- (5);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
The algorithm can begin at any node in the graph,
|
||||
but we will now assume that it begins
|
||||
at node 1.
|
||||
We may begin the search at any node in the graph,
|
||||
but we will now begin the search at node 1.
|
||||
|
||||
The search first proceeds to node 2:
|
||||
\begin{center}
|
||||
|
@ -305,7 +304,7 @@ to implement than depth-first search,
|
|||
because the algorithm visits nodes
|
||||
in different parts of the graph.
|
||||
A typical implementation is based on
|
||||
a queue of nodes to be processed.
|
||||
a queue that contains nodes.
|
||||
At each step, the next node in the queue
|
||||
will be processed.
|
||||
|
||||
|
@ -329,7 +328,7 @@ int z[N], e[N];
|
|||
so that the array \texttt{z} indicates
|
||||
which nodes the search has already visited
|
||||
and the array \texttt{e} will contain the
|
||||
minimum distance to all nodes in the graph.
|
||||
distances to all nodes in the graph.
|
||||
The search can be implemented as follows:
|
||||
\begin{lstlisting}
|
||||
z[s] = 1; e[x] = 0;
|
||||
|
@ -364,7 +363,7 @@ assume that the graph is undirected.
|
|||
A graph is connected if there is a path
|
||||
between any two nodes in the graph.
|
||||
Thus, we can check if a graph is connected
|
||||
by selecting an arbitrary node and
|
||||
by choosing an arbitrary node and
|
||||
finding out if we can reach all other nodes.
|
||||
|
||||
For example, in the graph
|
||||
|
@ -406,7 +405,7 @@ the following nodes:
|
|||
Since the search did not visit all the nodes,
|
||||
we can conclude that the graph is not connected.
|
||||
In a similar way, we can also find all connected components
|
||||
of a graph by iterating trough the nodes and always
|
||||
of a graph by iterating through the nodes and always
|
||||
starting a new depth-first search if the current node
|
||||
does not belong to any component yet.
|
||||
|
||||
|
@ -421,6 +420,24 @@ visited.
|
|||
For example, the graph
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\node[draw, circle] (2) at (7,5) {$2$};
|
||||
\node[draw, circle] (1) at (3,5) {$1$};
|
||||
\node[draw, circle] (3) at (5,4) {$3$};
|
||||
\node[draw, circle] (5) at (7,3) {$5$};
|
||||
\node[draw, circle] (4) at (3,3) {$4$};
|
||||
|
||||
\path[draw,thick,-] (1) -- (3);
|
||||
\path[draw,thick,-] (1) -- (4);
|
||||
\path[draw,thick,-] (3) -- (4);
|
||||
\path[draw,thick,-] (2) -- (5);
|
||||
\path[draw,thick,-] (2) -- (3);
|
||||
\path[draw,thick,-] (3) -- (5);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
contains two cycles and we can find one
|
||||
of them as follows:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\node[draw, circle,fill=lightgray] (2) at (7,5) {$2$};
|
||||
\node[draw, circle,fill=lightgray] (1) at (3,5) {$1$};
|
||||
\node[draw, circle,fill=lightgray] (3) at (5,4) {$3$};
|
||||
|
@ -440,7 +457,7 @@ For example, the graph
|
|||
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
contains a cycle because when we move from
|
||||
When we move from
|
||||
node 2 to node 5 it turns out
|
||||
that the neighbor 3 has already been visited.
|
||||
Thus, the graph contains a cycle that goes through node 3,
|
||||
|
@ -450,7 +467,8 @@ Another way to find out whether a graph contains a cycle
|
|||
is to simply calculate the number of nodes and edges
|
||||
in every component.
|
||||
If a component contains $c$ nodes and no cycle,
|
||||
it must contain exactly $c-1$ edges.
|
||||
it must contain exactly $c-1$ edges
|
||||
(so it has to be a tree).
|
||||
If there are $c$ or more edges, the component
|
||||
surely contains a cycle.
|
||||
|
||||
|
@ -489,7 +507,7 @@ For example, the graph
|
|||
\path[draw,thick,-] (5) -- (3);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
is not bipartite because a search from node 1
|
||||
is not bipartite, because a search from node 1
|
||||
proceeds as follows:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
|
@ -512,7 +530,7 @@ proceeds as follows:
|
|||
\path[draw=red,thick,->,line width=2pt] (5) -- (2);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
We notice that the color or both node 2 and node 5
|
||||
We notice that the color or both nodes 2 and 5
|
||||
is red, while they are adjacent nodes in the graph.
|
||||
Thus, the graph is not bipartite.
|
||||
|
||||
|
|
72
luku13.tex
72
luku13.tex
|
@ -7,7 +7,7 @@ of a graph
|
|||
is an important 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
|
||||
is to calculate the length of the shortest route
|
||||
between two cities, given the lengths of the roads.
|
||||
|
||||
In an unweighted graph, the length of a path equals
|
||||
|
@ -15,8 +15,8 @@ the number of edges in the path and we can
|
|||
simply use breadth-first search to find
|
||||
the shortest path.
|
||||
However, in this chapter we concentrate on
|
||||
weighted graphs,
|
||||
and more sophisticated algorithms
|
||||
weighted graphs
|
||||
where more sophisticated algorithms
|
||||
are needed
|
||||
for finding shortest paths.
|
||||
|
||||
|
@ -70,9 +70,8 @@ Each node in the graph is assigned a distance.
|
|||
Initially, the distance to the starting node is 0,
|
||||
and the distance to all other nodes is infinite.
|
||||
|
||||
The algorithm searches for edges that reduce the
|
||||
distances.
|
||||
First, all edges from node 1 reduce the distances:
|
||||
The algorithm searches for edges that reduce distances.
|
||||
First, all edges from node 1 reduce distances:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\node[draw, circle] (1) at (1,3) {1};
|
||||
|
@ -100,7 +99,7 @@ First, all edges from node 1 reduce the distances:
|
|||
\end{center}
|
||||
After this, edges
|
||||
$2 \rightarrow 5$ and $3 \rightarrow 4$
|
||||
reduce the distances:
|
||||
reduce distances:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\node[draw, circle] (1) at (1,3) {1};
|
||||
|
@ -156,7 +155,7 @@ and we have successfully
|
|||
calculated the shortest distance
|
||||
from the starting node to all other nodes.
|
||||
|
||||
For example, the smallest distance 3
|
||||
For example, the shortest distance 3
|
||||
from node 1 to node 5 corresponds to
|
||||
the following path:
|
||||
|
||||
|
@ -201,9 +200,9 @@ there is an edge to node $x$ with weight $w$.
|
|||
|
||||
The algorithm consists of $n-1$ rounds,
|
||||
and on each round the algorithm goes through
|
||||
all edges in the graph and tries to
|
||||
all edges of the graph and tries to
|
||||
reduce the distances.
|
||||
The algorithm builds an array \texttt{e}
|
||||
The algorithm constructs an array \texttt{e}
|
||||
that will contain the distance from $x$
|
||||
to all nodes in the graph.
|
||||
The initial value $10^9$ means infinity.
|
||||
|
@ -228,7 +227,7 @@ 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.
|
||||
be found faster than in $n-1$ rounds.
|
||||
Thus, a possible way to make the algorithm more efficient
|
||||
is to stop the algorithm if no distance
|
||||
can be reduced during a round.
|
||||
|
@ -272,7 +271,8 @@ using the Bellman–Ford algorithm by
|
|||
running the algorithm for $n$ rounds.
|
||||
If the last round reduces any distance,
|
||||
the graph contains a negative cycle.
|
||||
Note that this algorithm searches for
|
||||
Note that this algorithm can be used to
|
||||
search for
|
||||
a negative cycle in the whole graph
|
||||
regardless of the starting node.
|
||||
|
||||
|
@ -283,7 +283,7 @@ regardless of the starting node.
|
|||
The \key{SPFA algorithm} (''Shortest Path Faster Algorithm'')
|
||||
is a variant of the Bellman–Ford algorithm,
|
||||
that is often more efficient than the original algorithm.
|
||||
It does not go through all the edges on each round,
|
||||
The SPFA algorithm does not go through all the edges on each round,
|
||||
but instead, it chooses the edges to be examined
|
||||
in a more intelligent way.
|
||||
|
||||
|
@ -294,11 +294,11 @@ to the queue.
|
|||
Then, the algorithm always processes the
|
||||
first node in the queue, and when an edge
|
||||
$a \rightarrow b$ reduces a distance,
|
||||
node $b$ is added to the end of the queue.
|
||||
node $b$ is added to the queue.
|
||||
|
||||
The following implementation uses a
|
||||
\texttt{queue} structure \texttt{q}.
|
||||
In addition, the array \texttt{z} indicates
|
||||
\texttt{queue} \texttt{q}.
|
||||
In addition, an array \texttt{z} indicates
|
||||
if a node is already in the queue,
|
||||
in which case the algorithm does not add
|
||||
the node to the queue again.
|
||||
|
@ -321,11 +321,11 @@ while (!q.empty()) {
|
|||
|
||||
The efficiency of the SPFA algorithm depends
|
||||
on the structure of the graph:
|
||||
the algorithm is often very efficient,
|
||||
the algorithm is often 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.
|
||||
original Bellman–Ford algorithm.
|
||||
|
||||
\section{Dijkstra's algorithm}
|
||||
|
||||
|
@ -342,7 +342,7 @@ are no negative weight edges in the graph.
|
|||
|
||||
Like the Bellman–Ford algorithm,
|
||||
Dijkstra's algorithm maintains distances
|
||||
for the nodes and reduces them during the algorithm.
|
||||
to the nodes and reduces them during the search.
|
||||
Dijkstra's algorithm is efficient, because
|
||||
it only processes
|
||||
each edge in the graph once, using the fact
|
||||
|
@ -376,7 +376,7 @@ starting node is node 1:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
Like in the Bellman–Ford algorithm,
|
||||
intially 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 infinite.
|
||||
|
||||
At each step, Dijkstra's algorithm selects a node
|
||||
|
@ -529,7 +529,7 @@ However, Dijkstra's algorithm
|
|||
finds the path $1 \rightarrow 2 \rightarrow 4$
|
||||
by following the minimum weight edges.
|
||||
The algorithm does not take into account that
|
||||
on the lower path, the weight $-5$
|
||||
on the other path, the weight $-5$
|
||||
compensates the previous large weight $6$.
|
||||
|
||||
\subsubsection{Implementation}
|
||||
|
@ -550,7 +550,7 @@ can be retrieved in logarithmic time.
|
|||
|
||||
In the following implementation,
|
||||
the priority queue contains pairs whose first
|
||||
element is the current distance of the node and second
|
||||
element is the current distance to the node and second
|
||||
element is the identifier of the node.
|
||||
\begin{lstlisting}
|
||||
priority_queue<pair<int,int>> q;
|
||||
|
@ -559,12 +559,12 @@ A small difficulty is that in Dijkstra's algorithm,
|
|||
we should find the node with the \emph{minimum} distance,
|
||||
while the C++ priority queue finds the \emph{maximum}
|
||||
element as default.
|
||||
An easy solution is to use \emph{negative} distances,
|
||||
An easy trick is to use \emph{negative} distances,
|
||||
which allows us to directly use the C++ priority queue.
|
||||
|
||||
The code keeps track of processed nodes
|
||||
in the array \texttt{z},
|
||||
and maintains estimated distances in array \texttt{e}.
|
||||
in an array \texttt{z},
|
||||
and maintains the distances in an array \texttt{e}.
|
||||
Initially, the distance to the starting node is 0,
|
||||
and the distance to all other nodes is $10^9$ (infinite).
|
||||
|
||||
|
@ -587,8 +587,8 @@ while (!q.empty()) {
|
|||
|
||||
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.
|
||||
all nodes in the graph and adds for each edge
|
||||
at most one distance to the priority queue.
|
||||
|
||||
\section{Floyd–Warshall algorithm}
|
||||
|
||||
|
@ -605,7 +605,7 @@ 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
|
||||
After this the algorithm reduces the distances
|
||||
by using intermediate nodes in the paths.
|
||||
|
||||
\subsubsection{Example}
|
||||
|
@ -654,7 +654,7 @@ that can act as an intermediate node in paths from now on,
|
|||
and the algorithm reduces the distances in the array
|
||||
using this node.
|
||||
|
||||
On the first round, node 1 is the intermediate node.
|
||||
On the first round, node 1 is the new intermediate node.
|
||||
There is a new path between nodes 2 and 4
|
||||
with length 14, because node 1 connects them.
|
||||
There is also a new path
|
||||
|
@ -673,7 +673,7 @@ between nodes 2 and 5 with length 6.
|
|||
\end{center}
|
||||
\vspace{10pt}
|
||||
|
||||
On the second round, node 2 is the intermediate node.
|
||||
On the second round, node 2 is the new intermediate node.
|
||||
This creates new paths between nodes 1 and 3
|
||||
and between nodes 3 and 5:
|
||||
|
||||
|
@ -690,7 +690,7 @@ and between nodes 3 and 5:
|
|||
\end{center}
|
||||
\vspace{10pt}
|
||||
|
||||
On the third round, node 3 is the intermediate round.
|
||||
On the third round, node 3 is the new intermediate round.
|
||||
There is a new path between nodes 2 and 4:
|
||||
|
||||
\begin{center}
|
||||
|
@ -707,7 +707,7 @@ There is a new path between nodes 2 and 4:
|
|||
\vspace{10pt}
|
||||
|
||||
The algorithm continues like this,
|
||||
until all nodes have been intermediate nodes.
|
||||
until all nodes have been appointed intermediate nodes.
|
||||
After the algorithm has finished, the array contains
|
||||
the minimum distances between any two nodes:
|
||||
|
||||
|
@ -723,8 +723,8 @@ the minimum distances between any two nodes:
|
|||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
For example, the array indicates that the
|
||||
shortest path between nodes 2 and 4 has length 8.
|
||||
For example, the array tells us that the
|
||||
shortest distance between nodes 2 and 4 is 8.
|
||||
This corresponds to the following path:
|
||||
|
||||
\begin{center}
|
||||
|
@ -755,7 +755,7 @@ 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 between nodes $a$ and $b$.
|
||||
is the shortest distance between nodes $a$ and $b$.
|
||||
First, the algorithm initializes \texttt{d}
|
||||
using the adjacency matrix \texttt{v} of the graph
|
||||
($10^9$ means infinity):
|
||||
|
@ -770,7 +770,7 @@ for (int i = 1; i <= n; i++) {
|
|||
}
|
||||
\end{lstlisting}
|
||||
|
||||
After this, the shortest paths can be found as follows:
|
||||
After this, the shortest distances can be found as follows:
|
||||
|
||||
\begin{lstlisting}
|
||||
for (int k = 1; k <= n; k++) {
|
||||
|
|
22
luku14.tex
22
luku14.tex
|
@ -8,7 +8,7 @@ Removing any edge from a tree divides it
|
|||
into two components,
|
||||
and adding any edge to a tree creates a cycle.
|
||||
Moreover, there is always a unique path between any
|
||||
two nodes in a tree.
|
||||
two nodes of a tree.
|
||||
|
||||
For example, the following tree consists of 7 nodes and 6 edges:
|
||||
\begin{center}
|
||||
|
@ -33,7 +33,7 @@ For example, the following tree consists of 7 nodes and 6 edges:
|
|||
|
||||
The \key{leaves} of a tree are the nodes
|
||||
with degree 1, i.e., with only one neighbor.
|
||||
For example, the leaves in the above tree
|
||||
For example, the leaves of the above tree
|
||||
are nodes 3, 5, 6 and 7.
|
||||
|
||||
\index{root}
|
||||
|
@ -73,7 +73,7 @@ is its upper neighbor.
|
|||
Each node has exactly one parent,
|
||||
except for the root that does not have a parent.
|
||||
For example, in the above tree,
|
||||
the childern of node 4 are nodes 3 and 7,
|
||||
the children of node 4 are nodes 3 and 7,
|
||||
and the parent is node 1.
|
||||
|
||||
\index{subtree}
|
||||
|
@ -89,9 +89,9 @@ consists of nodes 4, 3 and 7.
|
|||
|
||||
Depth-first search and breadth-first search
|
||||
can be used for traversing the nodes in a tree.
|
||||
However, the traversal is easier to implement than
|
||||
in a general graph because
|
||||
there are no cycles in the tree, and it is not
|
||||
The traversal of a tree is easier to implement than
|
||||
that of a general graph, because
|
||||
there are no cycles in the tree and it is not
|
||||
possible to reach a node from multiple directions.
|
||||
|
||||
The typical way to traverse a tree is to start
|
||||
|
@ -232,9 +232,9 @@ the longest path from node 1 to a leaf has length 2
|
|||
$1 \rightarrow 4 \rightarrow 7$ or $1 \rightarrow 2 \rightarrow 6$).
|
||||
After this, the algorithm calculates for each node
|
||||
$x$ the length of the longest path where $x$
|
||||
is the turning point of the path.
|
||||
is the highest point of the path.
|
||||
The longest such path can be found by choosing
|
||||
two children with longest paths two leaves.
|
||||
two children with longest paths to leaves.
|
||||
For example, in the above graph,
|
||||
nodes 2 and 4 yield the longest path for node 1.
|
||||
|
||||
|
@ -357,7 +357,7 @@ In the example graph, the distances are as follows:
|
|||
\end{center}
|
||||
\end{samepage}
|
||||
For example, the farthest node from node 4
|
||||
in the direction of node 1 is node 6, and the distance to this
|
||||
in the direction of node 1 is node 6, and the distance to that
|
||||
node is 3 using the path
|
||||
$4 \rightarrow 1 \rightarrow 2 \rightarrow 6$.
|
||||
|
||||
|
@ -500,7 +500,7 @@ For example, the following tree is a binary tree:
|
|||
|
||||
The nodes in a binary tree have three natural
|
||||
orderings that correspond to different ways to
|
||||
recursively traverse the nodes:
|
||||
recursively traverse the tree:
|
||||
|
||||
\begin{itemize}
|
||||
\item \key{pre-order}: first process the root,
|
||||
|
@ -519,7 +519,7 @@ and in post-order $[4,6,5,2,7,3,1]$.
|
|||
|
||||
If we know the pre-order and in-order
|
||||
of a tree, we can reconstruct the exact structure of the tree.
|
||||
For example, the tree above is the only possible tree
|
||||
For example, the above tree is the only possible tree
|
||||
with pre-order $[1,2,4,5,6,3,7]$ and
|
||||
in-order $[4,2,6,5,1,3,7]$.
|
||||
In a similar way, the post-order and in-order
|
||||
|
|
46
luku15.tex
46
luku15.tex
|
@ -4,7 +4,7 @@
|
|||
|
||||
A \key{spanning tree} of a graph consists of
|
||||
the nodes of the graph and some of the
|
||||
edges of the graph so that there is a unique path
|
||||
edges of the graph so that there is a path
|
||||
between any two nodes.
|
||||
Like trees in general, spanning trees are
|
||||
connected and acyclic.
|
||||
|
@ -54,7 +54,7 @@ $3+5+9+3+2=22$.
|
|||
|
||||
A \key{minimum spanning tree}
|
||||
is a spanning tree whose weight is as small as possible.
|
||||
The weight of a minimum spanning tree for the above graph
|
||||
The weight of a minimum spanning tree for the example graph
|
||||
is 20, and such a tree can be constructed as follows:
|
||||
|
||||
\begin{center}
|
||||
|
@ -82,7 +82,7 @@ is 20, and such a tree can be constructed as follows:
|
|||
In a similar way, a \key{maximum spanning tree}
|
||||
is a spanning tree whose weight is as large as possible.
|
||||
The weight of a maximum spanning tree for the
|
||||
above graph is 32:
|
||||
example graph is 32:
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -302,7 +302,7 @@ will find a minimum spanning tree?
|
|||
Let us see what happens if the minimum weight edge of
|
||||
the graph is not included in the spanning tree.
|
||||
For example, suppose that a spanning tree
|
||||
for the above graph would not contain the
|
||||
for the previous graph would not contain the
|
||||
minimum weight edge 5--6.
|
||||
We do not know the exact structure of such a spanning tree,
|
||||
but in any case it has to contain some edges.
|
||||
|
@ -377,7 +377,7 @@ for (...) {
|
|||
The loop goes through the edges in the list
|
||||
and always processes an edge $a$--$b$
|
||||
where $a$ and $b$ are two nodes.
|
||||
The code uses two functions:
|
||||
Two functions are needed:
|
||||
the function \texttt{same} determines
|
||||
if the nodes are in the same component,
|
||||
and the function \texttt{union}
|
||||
|
@ -386,10 +386,10 @@ joins the components that contain nodes $a$ and $b$.
|
|||
The problem is how to efficiently implement
|
||||
the functions \texttt{same} and \texttt{union}.
|
||||
One possibility is to implement the function
|
||||
\texttt{same} as graph traversal and check if
|
||||
we can reach node $b$ from node $a$.
|
||||
\texttt{same} as a graph traversal and check if
|
||||
we can get from node $a$ to node $b$.
|
||||
However, the time complexity of such a function
|
||||
would be $O(n+m)$,
|
||||
would be $O(n+m)$
|
||||
and the resulting algorithm would be slow,
|
||||
because the function \texttt{same} will be called for each edge in the graph.
|
||||
|
||||
|
@ -415,7 +415,7 @@ of the set that contains a given element.
|
|||
|
||||
In a union-find structure, one element in each set
|
||||
is the representative of the set,
|
||||
and there is a chain from any other element in the
|
||||
and there is a chain from any other element of the
|
||||
set to the representative.
|
||||
For example, assume that the sets are
|
||||
$\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$:
|
||||
|
@ -439,13 +439,13 @@ $\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$:
|
|||
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
In this example the representatives
|
||||
In this case the representatives
|
||||
of the sets are 4, 5 and 2.
|
||||
For each element, we can find its representative
|
||||
by following the chain that begins at the element.
|
||||
For example, the element 2 is the representative
|
||||
for the element 6, because
|
||||
there is a chain $6 \rightarrow 3 \rightarrow 2$.
|
||||
we follow the chain $6 \rightarrow 3 \rightarrow 2$.
|
||||
Two elements belong to the same set exactly when
|
||||
their representatives are the same.
|
||||
|
||||
|
@ -478,20 +478,21 @@ can be joined as follows:
|
|||
|
||||
The resulting set contains the elements
|
||||
$\{1,2,3,4,6,7,8\}$.
|
||||
From this on, the element 2 will be the representative
|
||||
From this on, the element 2 is the representative
|
||||
for the entire set and the old representative 4
|
||||
will point to the element 2.
|
||||
points to the element 2.
|
||||
|
||||
The efficiency of the structure depends on
|
||||
the way the sets are joined.
|
||||
The efficiency of the union-find structure depends on
|
||||
how the sets are joined.
|
||||
It turns out that we can follow a simple strategy:
|
||||
always connect the representative of the
|
||||
smaller set to the representative of the larger set
|
||||
(or if the sets are of equal size,
|
||||
we can make an arbitrary choice).
|
||||
Using this strategy, the length of any chain
|
||||
will be $O(\log n)$, so we can always efficiently
|
||||
find the representative of any element by following the chain.
|
||||
will be $O(\log n)$, so we can
|
||||
find the representative of any element
|
||||
efficiently by following the corresponding chain.
|
||||
|
||||
\subsubsection{Implementation}
|
||||
|
||||
|
@ -570,9 +571,9 @@ the smaller set to the larger set.
|
|||
for finding a minimum spanning tree.
|
||||
The algorithm first adds an arbitrary node
|
||||
to the tree.
|
||||
After this, the algorithm always selects an edge
|
||||
whose weight is as small as possible and
|
||||
that adds a new node to the tree.
|
||||
After this, the algorithm always chooses
|
||||
a minimum-weight edge that
|
||||
adds a new node to the tree.
|
||||
Finally, all nodes have been added to the tree
|
||||
and a minimum spanning tree has been found.
|
||||
|
||||
|
@ -627,8 +628,9 @@ Initially, there are no edges between the nodes:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
An arbitrary node can be the starting node,
|
||||
so let us select node 1.
|
||||
First, an edge with weight 3 connects nodes 1 and 2:
|
||||
so let us choose node 1.
|
||||
First, we add node 2 that is connected by
|
||||
an edge of weight 3:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
\node[draw, circle] (1) at (1.5,2) {$1$};
|
||||
|
|
Loading…
Reference in New Issue