Corrections

This commit is contained in:
Antti H S Laaksonen 2017-02-17 22:13:30 +02:00
parent f478d7044c
commit c447a6f33b
5 changed files with 186 additions and 123 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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 BellmanFord 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 BellmanFord 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 BellmanFord algorithm.
original BellmanFord algorithm.
\section{Dijkstra's algorithm}
@ -342,7 +342,7 @@ are no negative weight edges in the graph.
Like the BellmanFord 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 BellmanFord 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{FloydWarshall 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 @@ FloydWarshall 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++) {

View File

@ -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

View File

@ -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$};