Improve language
This commit is contained in:
parent
7aad9cc8d9
commit
5a298088b9
|
@ -22,8 +22,7 @@ and study different ways to represent graphs in algorithms.
|
|||
\index{edge}
|
||||
|
||||
A \key{graph} consists of \key{nodes}
|
||||
and \key{edges} between them.
|
||||
In this book,
|
||||
and \key{edges}. In this book,
|
||||
the variable $n$ denotes the number of nodes
|
||||
in a graph, and the variable $m$ denotes
|
||||
the number of edges.
|
||||
|
@ -57,7 +56,7 @@ through edges of the graph.
|
|||
The \key{length} of a path is the number of
|
||||
edges in it.
|
||||
For example, the above graph contains
|
||||
the path $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$
|
||||
a path $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$
|
||||
from node 1 to node 5:
|
||||
|
||||
\begin{center}
|
||||
|
@ -87,7 +86,7 @@ from node 1 to node 5:
|
|||
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 cycle $1 \rightarrow 3 \rightarrow 4 \rightarrow 1$.
|
||||
A path is \key{simple} if each node appears
|
||||
at most once in the path.
|
||||
|
||||
|
@ -106,7 +105,7 @@ at most once in the path.
|
|||
|
||||
\index{connected graph}
|
||||
|
||||
A graph is \key{connected} if there is path
|
||||
A graph is \key{connected} if there is a path
|
||||
between any two nodes.
|
||||
For example, the following graph is connected:
|
||||
\begin{center}
|
||||
|
@ -175,7 +174,7 @@ $\{8\}$.
|
|||
A \key{tree} is a connected graph
|
||||
that consists of $n$ nodes and $n-1$ edges.
|
||||
There is a unique path
|
||||
between any two nodes in a tree.
|
||||
between any two nodes of a tree.
|
||||
For example, the following graph is a tree:
|
||||
|
||||
\begin{center}
|
||||
|
@ -220,7 +219,7 @@ For example, the following graph is directed:
|
|||
\end{center}
|
||||
|
||||
The above graph contains
|
||||
the path $3 \rightarrow 1 \rightarrow 2 \rightarrow 5$
|
||||
a 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$.
|
||||
|
||||
|
@ -230,7 +229,7 @@ but there is no path from node $5$ to node $3$.
|
|||
|
||||
In a \key{weighted} graph, each edge is assigned
|
||||
a \key{weight}.
|
||||
Often the weights are interpreted as edge lengths.
|
||||
The weights are often interpreted as edge lengths.
|
||||
For example, the following graph is weighted:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -249,10 +248,10 @@ For example, the following graph is weighted:
|
|||
\end{center}
|
||||
|
||||
The length of a path in a weighted graph
|
||||
is the sum of edge weights on the path.
|
||||
is the sum of the edge weights on the path.
|
||||
For example, in the above graph,
|
||||
the length of the path
|
||||
$1 \rightarrow 2 \rightarrow 5$ is $12$
|
||||
$1 \rightarrow 2 \rightarrow 5$ is $12$,
|
||||
and the length of the path
|
||||
$1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ is $11$.
|
||||
The latter path is the \key{shortest} path from node $1$ to node $5$.
|
||||
|
@ -313,7 +312,7 @@ that end at the node,
|
|||
and the \key{outdegree} of a node
|
||||
is the number of edges that start at the node.
|
||||
For example, in the following graph,
|
||||
the indegree of node 2 is 2
|
||||
the indegree of node 2 is 2,
|
||||
and the outdegree of node 2 is 1.
|
||||
|
||||
\begin{center}
|
||||
|
@ -548,7 +547,7 @@ adj[3].push_back({4,5});
|
|||
adj[4].push_back({1,2});
|
||||
\end{lstlisting}
|
||||
|
||||
The benefit in using adjacency lists is that
|
||||
The benefit of using adjacency lists is that
|
||||
we can efficiently find the nodes to which
|
||||
we can move from a given node through an edge.
|
||||
For example, the following loop goes through all nodes
|
||||
|
@ -677,7 +676,7 @@ corresponds to the following matrix:
|
|||
\end{center}
|
||||
\end{samepage}
|
||||
|
||||
The drawback in the adjacency matrix representation
|
||||
The drawback of the adjacency matrix representation
|
||||
is that there are $n^2$ elements in the matrix
|
||||
and usually most of them are zero.
|
||||
For this reason, the representation cannot be used
|
||||
|
@ -753,7 +752,7 @@ For example, the graph
|
|||
\begin{samepage}
|
||||
can be represented as follows\footnote{In some older compilers, the function
|
||||
\texttt{make\_tuple} must be used instead of the braces (for example,
|
||||
\texttt{make\_tuple(1,2,5)} instead of \texttt{\{1,2,5\}}.}:
|
||||
\texttt{make\_tuple(1,2,5)} instead of \texttt{\{1,2,5\}}).}:
|
||||
\begin{lstlisting}
|
||||
edges.push_back({1,2,5});
|
||||
edges.push_back({2,3,7});
|
||||
|
|
|
@ -19,7 +19,7 @@ is a straightforward graph traversal technique.
|
|||
The algorithm begins at a starting node,
|
||||
and proceeds to all other nodes that are
|
||||
reachable from the starting node using
|
||||
the edges in the graph.
|
||||
the edges of the graph.
|
||||
|
||||
Depth-first search always follows a single
|
||||
path in the graph as long as it finds
|
||||
|
@ -48,8 +48,8 @@ the following graph:
|
|||
\path[draw,thick,-] (2) -- (5);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
We may begin the search at any node in the graph,
|
||||
but we will now begin the search at node 1.
|
||||
We may begin the search at any node of the graph;
|
||||
now we will begin the search at node 1.
|
||||
|
||||
The search first proceeds to node 2:
|
||||
\begin{center}
|
||||
|
@ -91,7 +91,7 @@ After this, nodes 3 and 5 will be visited:
|
|||
\end{center}
|
||||
The neighbors of node 5 are 2 and 3,
|
||||
but the search has already visited both of them,
|
||||
so it is time to return to previous nodes.
|
||||
so it is time to return to the previous nodes.
|
||||
Also the neighbors of nodes 3 and 2
|
||||
have been visited, so we next move
|
||||
from node 1 to node 4:
|
||||
|
@ -174,7 +174,7 @@ have been visited.
|
|||
|
||||
\subsubsection*{Example}
|
||||
|
||||
Let us consider how the algorithm processes
|
||||
Let us consider how breadth-first search processes
|
||||
the following graph:
|
||||
|
||||
\begin{center}
|
||||
|
@ -186,7 +186,6 @@ the following graph:
|
|||
\node[draw, circle] (5) at (3,3) {$5$};
|
||||
\node[draw, circle] (6) at (5,3) {$6$};
|
||||
|
||||
|
||||
\path[draw,thick,-] (1) -- (2);
|
||||
\path[draw,thick,-] (2) -- (3);
|
||||
\path[draw,thick,-] (1) -- (4);
|
||||
|
@ -195,7 +194,7 @@ the following graph:
|
|||
\path[draw,thick,-] (5) -- (6);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
Suppose again that the search begins at node 1.
|
||||
Suppose that the search begins at node 1.
|
||||
First, we process all nodes that can be reached
|
||||
from node 1 using a single edge:
|
||||
\begin{center}
|
||||
|
@ -276,7 +275,7 @@ Finally, we visit node 6:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
Now we have calculated the distances
|
||||
from the starting node to all nodes in the graph.
|
||||
from the starting node to all nodes of the graph.
|
||||
The distances are as follows:
|
||||
|
||||
\begin{tabular}{ll}
|
||||
|
@ -294,7 +293,7 @@ node & distance \\
|
|||
|
||||
Like in depth-first search,
|
||||
the time complexity of breadth-first search
|
||||
is $O(n+m)$ where $n$ is the number of nodes
|
||||
is $O(n+m)$, where $n$ is the number of nodes
|
||||
and $m$ is the number of edges.
|
||||
|
||||
\subsubsection*{Implementation}
|
||||
|
@ -318,15 +317,15 @@ int dist[N];
|
|||
\end{lstlisting}
|
||||
|
||||
The queue \texttt{q}
|
||||
contains the nodes in increasing order
|
||||
of their distance.
|
||||
contains nodes to be processed
|
||||
in increasing order of their distance.
|
||||
New nodes are always added to the end
|
||||
of the queue, and the node at the beginning
|
||||
of the queue is the next node to be processed.
|
||||
The array \texttt{vis} indicates
|
||||
which nodes the search has already visited,
|
||||
and the array \texttt{dist} will contain the
|
||||
distances to all nodes in the graph.
|
||||
distances from the starting node to all nodes of the graph.
|
||||
|
||||
The search can be implemented as follows,
|
||||
starting at node $x$:
|
||||
|
@ -349,9 +348,9 @@ while (!q.empty()) {
|
|||
\section{Applications}
|
||||
|
||||
Using the graph traversal algorithms,
|
||||
we can check many properties of the graph.
|
||||
Usually, either depth-first search or
|
||||
bredth-first search can be used,
|
||||
we can check many properties of graphs.
|
||||
Usually, both depth-first search and
|
||||
bredth-first search may be used,
|
||||
but in practice, depth-first search
|
||||
is a better choice, because it is
|
||||
easier to implement.
|
||||
|
@ -363,9 +362,9 @@ assume that the graph is undirected.
|
|||
\index{connected graph}
|
||||
|
||||
A graph is connected if there is a path
|
||||
between any two nodes in the graph.
|
||||
between any two nodes of the graph.
|
||||
Thus, we can check if a graph is connected
|
||||
by choosing an arbitrary node and
|
||||
by starting at an arbitrary node and
|
||||
finding out if we can reach all other nodes.
|
||||
|
||||
For example, in the graph
|
||||
|
@ -459,9 +458,8 @@ of them as follows:
|
|||
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
When we move from
|
||||
node 2 to node 5 it turns out
|
||||
that the neighbor 3 has already been visited.
|
||||
After moving from node 2 to node 5 we notice that
|
||||
the neighbor 3 of node 5 has already been visited.
|
||||
Thus, the graph contains a cycle that goes through node 3,
|
||||
for example, $3 \rightarrow 2 \rightarrow 5 \rightarrow 3$.
|
||||
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
\index{shortest path}
|
||||
|
||||
Finding the shortest path between two nodes
|
||||
Finding a shortest path between two nodes
|
||||
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 shortest route
|
||||
practical applications.
|
||||
For example, a natural problem related to a road network
|
||||
is to calculate the shortest possible length of a 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
|
||||
the number of its edges, and we can
|
||||
simply use breadth-first search to find
|
||||
the shortest path.
|
||||
However, in this chapter we concentrate on
|
||||
a shortest path.
|
||||
However, in this chapter we focus on
|
||||
weighted graphs
|
||||
where more sophisticated algorithms
|
||||
are needed
|
||||
|
@ -26,9 +26,9 @@ for finding shortest paths.
|
|||
|
||||
The \key{Bellman–Ford algorithm}\footnote{The algorithm is named after
|
||||
R. E. Bellman and L. R. Ford who published it independently
|
||||
in 1958 and 1956, respectively \cite{bel58,for56a}.} finds the
|
||||
in 1958 and 1956, respectively \cite{bel58,for56a}.} finds
|
||||
shortest paths from a starting node to all
|
||||
other nodes in the graph.
|
||||
nodes of the graph.
|
||||
The algorithm can process all kinds of graphs,
|
||||
provided that the graph does not contain a
|
||||
cycle with negative length.
|
||||
|
@ -36,7 +36,7 @@ If the graph contains a negative cycle,
|
|||
the algorithm can detect this.
|
||||
|
||||
The algorithm keeps track of distances
|
||||
from the starting node to other nodes.
|
||||
from the starting node to all nodes of the graph.
|
||||
Initially, the distance to the starting node is 0
|
||||
and the distance to all other nodes in infinite.
|
||||
The algorithm reduces the distances by finding
|
||||
|
@ -68,7 +68,7 @@ works in the following graph:
|
|||
\path[draw,thick,-] (1) -- node[font=\small,label=above:7] {} (4);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
Each node in the graph is assigned a distance.
|
||||
Each node of the graph is assigned a distance.
|
||||
Initially, the distance to the starting node is 0,
|
||||
and the distance to all other nodes is infinite.
|
||||
|
||||
|
@ -152,10 +152,10 @@ Finally, there is one more change:
|
|||
\end{center}
|
||||
|
||||
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
|
||||
calculated the shortest distance
|
||||
from the starting node to all other nodes.
|
||||
calculated the shortest distances
|
||||
from the starting node to all nodes of the graph.
|
||||
|
||||
For example, the shortest distance 3
|
||||
from node 1 to node 5 corresponds to
|
||||
|
@ -190,8 +190,8 @@ the following path:
|
|||
\subsubsection{Implementation}
|
||||
|
||||
The following implementation of the
|
||||
Bellman–Ford algorithm finds the shortest distances
|
||||
from a node $x$ to all other nodes in the graph.
|
||||
Bellman–Ford algorithm determines the shortest distances
|
||||
from a node $x$ to all nodes of the graph.
|
||||
The code assumes that the graph is stored
|
||||
as an edge list \texttt{edges}
|
||||
that consists of tuples of the form $(a,b,w)$,
|
||||
|
@ -203,8 +203,8 @@ and on each round the algorithm goes through
|
|||
all edges of the graph and tries to
|
||||
reduce the distances.
|
||||
The algorithm constructs an array \texttt{dist}
|
||||
that will contain the distance from $x$
|
||||
to all nodes in the graph.
|
||||
that will contain the distances from $x$
|
||||
to all nodes of the graph.
|
||||
The constant \texttt{INF} denotes an infinite distance.
|
||||
|
||||
\begin{lstlisting}
|
||||
|
@ -236,7 +236,7 @@ can be reduced during a round.
|
|||
|
||||
\index{negative cycle}
|
||||
|
||||
The Bellman–Ford algorithm can be also used to
|
||||
The Bellman–Ford algorithm can also be used to
|
||||
check if the graph contains a cycle with negative length.
|
||||
For example, the graph
|
||||
|
||||
|
@ -260,8 +260,8 @@ $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
|
||||
we can shorten infinitely many times
|
||||
any path that contains the cycle by repeating the cycle
|
||||
again and again.
|
||||
Thus, the concept of a shortest path
|
||||
is not meaningful in this situation.
|
||||
|
@ -333,10 +333,10 @@ original Bellman–Ford algorithm.
|
|||
|
||||
\key{Dijkstra's algorithm}\footnote{E. W. Dijkstra published the algorithm in 1959 \cite{dij59};
|
||||
however, his original paper does not mention how to implement the algorithm efficiently.}
|
||||
finds the shortest
|
||||
paths from the starting node to all other nodes,
|
||||
finds shortest
|
||||
paths from the starting node to all nodes of the graph,
|
||||
like the Bellman–Ford algorithm.
|
||||
The benefit in Dijsktra's algorithm is that
|
||||
The benefit of Dijsktra's algorithm is that
|
||||
it is more efficient and can be used for
|
||||
processing large graphs.
|
||||
However, the algorithm requires that there
|
||||
|
@ -415,7 +415,8 @@ and reduces the distances using them:
|
|||
\path[draw=red,thick,->,line width=2pt] (4) -- (5);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
The edges from node 1 reduced distances to
|
||||
In this case,
|
||||
the edges from node 1 reduced the distances of
|
||||
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:
|
||||
|
@ -538,7 +539,7 @@ compensates the previous large weight $6$.
|
|||
|
||||
The following implementation of Dijkstra's algorithm
|
||||
calculates the minimum distances from a node $x$
|
||||
to all other nodes.
|
||||
to other nodes of the graph.
|
||||
The graph is stored as adjacency lists
|
||||
so that \texttt{adj[$a$]} contains a pair $(b,w)$
|
||||
always when there is an edge from node $a$ to node $b$
|
||||
|
@ -552,13 +553,14 @@ that contains the nodes ordered by their distances.
|
|||
Using a priority queue, the next node to be processed
|
||||
can be retrieved in logarithmic time.
|
||||
|
||||
The following implementation uses a priority queue
|
||||
\texttt{q} that contains pairs of the form $(-d,x)$:
|
||||
the current distance to node $x$ is $d$.
|
||||
In the following code,
|
||||
the priority queue
|
||||
\texttt{q} contains pairs of the form $(-d,x)$,
|
||||
meaning that the current distance to node $x$ is $d$.
|
||||
The array $\texttt{dist}$ contains the distance to
|
||||
each node, and the array $\texttt{ready}$ indicates
|
||||
whether a node has been processed.
|
||||
Initially the distance to $0$ to $x$ and $\infty$ to all other nodes.
|
||||
Initially the distance is $0$ to $x$ and $\infty$ to all other nodes.
|
||||
|
||||
\begin{lstlisting}
|
||||
for (int i = 1; i <= n; i++) dist[i] = INF;
|
||||
|
@ -580,8 +582,9 @@ while (!q.empty()) {
|
|||
|
||||
Note that the priority queue contains \emph{negative}
|
||||
distances to nodes.
|
||||
The reason for this is that the C++ priority queue finds maximum
|
||||
elements by default while we want to find minimum elements.
|
||||
The reason for this is that the
|
||||
default version of the C++ priority queue finds maximum
|
||||
elements, while we want to find minimum elements.
|
||||
By using negative distances,
|
||||
we can directly use the default version of the C++ priority queue\footnote{Of
|
||||
course, we could also declare the priority queue as in Chapter 4.5
|
||||
|
@ -591,8 +594,8 @@ node in the priority queue; however, only the instance with the
|
|||
minimum distance will be processed.
|
||||
|
||||
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
|
||||
$O(n+m \log m)$, because the algorithm goes through
|
||||
all nodes of the graph and adds for each edge
|
||||
at most one distance to the priority queue.
|
||||
|
||||
\section{Floyd–Warshall algorithm}
|
||||
|
@ -602,9 +605,9 @@ at most one distance to the priority queue.
|
|||
The \key{Floyd–Warshall algorithm}\footnote{The algorithm
|
||||
is named after R. W. Floyd and S. Warshall
|
||||
who published it independently in 1962 \cite{flo62,war62}.}
|
||||
is an alternative way to approach the problem
|
||||
provides an alternative way to approach the problem
|
||||
of finding shortest paths.
|
||||
Unlike the other algorithms in this chapter,
|
||||
Unlike the other algorithms of this chapter,
|
||||
it finds all shortest paths between the nodes
|
||||
in a single run.
|
||||
|
||||
|
@ -775,9 +778,7 @@ for (int i = 1; i <= n; i++) {
|
|||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
After this, the shortest distances can be found as follows:
|
||||
|
||||
\begin{lstlisting}
|
||||
for (int k = 1; k <= n; k++) {
|
||||
for (int i = 1; i <= n; i++) {
|
||||
|
|
|
@ -79,7 +79,7 @@ and the parent is node 1.
|
|||
\index{subtree}
|
||||
|
||||
The structure of a rooted tree is \emph{recursive}:
|
||||
each node in the tree is the root of a \key{subtree}
|
||||
each node of the tree acts as the root of a \key{subtree}
|
||||
that contains the node itself and all other nodes
|
||||
that can be reached by traversing down the tree.
|
||||
For example, in the above tree, the subtree of node 4
|
||||
|
@ -88,7 +88,7 @@ consists of nodes 4, 3 and 7.
|
|||
\section{Tree traversal}
|
||||
|
||||
Depth-first search and breadth-first search
|
||||
can be used for traversing the nodes in a tree.
|
||||
can be used for traversing the nodes of a tree.
|
||||
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
|
||||
|
@ -129,8 +129,7 @@ to proceed to any direction in the tree.
|
|||
Dynamic programming can be used to calculate
|
||||
some information during a tree traversal.
|
||||
Using dynamic programming, we can, for example,
|
||||
calculate in $O(n)$ time for each node
|
||||
in a rooted tree the
|
||||
calculate in $O(n)$ time for each node of a rooted tree the
|
||||
number of nodes in its subtree
|
||||
or the length of the longest path from the node
|
||||
to a leaf.
|
||||
|
@ -158,8 +157,8 @@ void dfs(int s, int e) {
|
|||
\index{diameter}
|
||||
|
||||
The \key{diameter} of a tree
|
||||
is the length of the longest path
|
||||
between two nodes in the tree.
|
||||
is the maximum length of a path
|
||||
between two nodes of the tree.
|
||||
For example, in the tree
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -194,12 +193,11 @@ to calculate the diameter.
|
|||
First, we root the tree arbitrarily.
|
||||
After this, we use dynamic programming
|
||||
to calculate for each node $x$
|
||||
the length of the longest path that begins at some leaf,
|
||||
the maximum length of a path that begins at some leaf,
|
||||
ascends to $x$ and then descends to another leaf.
|
||||
The length of the
|
||||
longest such path equals the diameter of the tree.
|
||||
The maximum length of such a path equals the diameter of the tree.
|
||||
|
||||
In the example graph, the longest path begins at node 7,
|
||||
In the example graph, a longest path begins at node 7,
|
||||
ascends to node 1, and then descends to node 6:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -225,18 +223,18 @@ ascends to node 1, and then descends to node 6:
|
|||
\end{center}
|
||||
|
||||
The algorithm first calculates for each node $x$
|
||||
the length of the longest path from $x$ to a leaf.
|
||||
the maximum length of a path from $x$ to a leaf.
|
||||
For example, in the above tree,
|
||||
the longest path from node 1 to a leaf has length 2
|
||||
a longest path from node 1 to a leaf has length 2
|
||||
(the path can be $1 \rightarrow 4 \rightarrow 3$,
|
||||
$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$
|
||||
$x$ the maximum length of a path where $x$
|
||||
is the highest point of the path.
|
||||
The longest such path can be found by choosing
|
||||
Such a path can be found by choosing
|
||||
two children with longest paths to leaves.
|
||||
For example, in the above graph,
|
||||
nodes 2 and 4 yield the longest path for node 1.
|
||||
nodes 2 and 4 yield a longest path for node 1.
|
||||
|
||||
\subsubsection{Algorithm 2}
|
||||
|
||||
|
@ -319,7 +317,7 @@ a starting node of a path that corresponds to the diameter.
|
|||
\section{Distances between nodes}
|
||||
|
||||
A more difficult problem is to calculate
|
||||
for each node in the tree and for each direction,
|
||||
for each node of the tree and for each direction,
|
||||
the maximum distance to a node in that direction.
|
||||
It turns out that this can be calculated in
|
||||
$O(n)$ time using dynamic programming.
|
||||
|
@ -498,7 +496,7 @@ For example, the following tree is a binary tree:
|
|||
\index{in-order}
|
||||
\index{post-order}
|
||||
|
||||
The nodes in a binary tree have three natural
|
||||
The nodes of a binary tree have three natural
|
||||
orderings that correspond to different ways to
|
||||
recursively traverse the tree:
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ A possible spanning tree for the graph is as follows:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
The weight of a spanning tree is the sum of the edge weights.
|
||||
The weight of a spanning tree is the sum of its edge weights.
|
||||
For example, the weight of the above spanning tree is
|
||||
$3+5+9+3+2=22$.
|
||||
|
||||
|
@ -103,9 +103,8 @@ example graph is 32:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
Note that there may be several
|
||||
minimum and maximum spanning trees
|
||||
for a graph,
|
||||
Note that a graph may have several
|
||||
minimum and maximum spanning trees,
|
||||
so the trees are not unique.
|
||||
|
||||
This chapter discusses algorithms
|
||||
|
@ -166,7 +165,7 @@ following graph:
|
|||
\end{samepage}
|
||||
|
||||
\begin{samepage}
|
||||
The first step in the algorithm is to sort the
|
||||
The first step of the algorithm is to sort the
|
||||
edges in increasing order of their weights.
|
||||
The result is the following list:
|
||||
|
||||
|
@ -211,7 +210,7 @@ Initially, each node is in its own component:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
The first edge to be added to the tree is
|
||||
the edge 5--6 that creates the component $\{5,6\}$
|
||||
the edge 5--6 that creates a component $\{5,6\}$
|
||||
by joining the components $\{5\}$ and $\{6\}$:
|
||||
|
||||
\begin{center}
|
||||
|
@ -301,7 +300,7 @@ Why does the greedy strategy guarantee that we
|
|||
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.
|
||||
the graph is \emph{not} included in the spanning tree.
|
||||
For example, suppose that a spanning tree
|
||||
for the previous graph would not contain the
|
||||
minimum weight edge 5--6.
|
||||
|
@ -362,8 +361,8 @@ always produces a minimum spanning tree.
|
|||
\subsubsection{Implementation}
|
||||
|
||||
When implementing Kruskal's algorithm,
|
||||
the edge list representation of the graph
|
||||
is convenient.
|
||||
it is convenient to use
|
||||
the edge list representation of the graph.
|
||||
The first phase of the algorithm sorts the
|
||||
edges in the list in $O(m \log m)$ time.
|
||||
After this, the second phase of the algorithm
|
||||
|
@ -380,9 +379,9 @@ and always processes an edge $a$--$b$
|
|||
where $a$ and $b$ are two nodes.
|
||||
Two functions are needed:
|
||||
the function \texttt{same} determines
|
||||
if the nodes are in the same component,
|
||||
if $a$ and $b$ are in the same component,
|
||||
and the function \texttt{unite}
|
||||
joins the components that contain nodes $a$ and $b$.
|
||||
joins the components that contain $a$ and $b$.
|
||||
|
||||
The problem is how to efficiently implement
|
||||
the functions \texttt{same} and \texttt{unite}.
|
||||
|
@ -446,7 +445,7 @@ $\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$:
|
|||
\end{center}
|
||||
In this case the representatives
|
||||
of the sets are 4, 5 and 2.
|
||||
For each element, we can find its representative
|
||||
We can find the representative of any element
|
||||
by following the chain that begins at the element.
|
||||
For example, the element 2 is the representative
|
||||
for the element 6, because
|
||||
|
@ -456,7 +455,7 @@ their representatives are the same.
|
|||
|
||||
Two sets can be joined by connecting the
|
||||
representative of one set to the
|
||||
representative of another set.
|
||||
representative of the other set.
|
||||
For example, the sets
|
||||
$\{1,4,7\}$ and $\{2,3,6,8\}$
|
||||
can be joined as follows:
|
||||
|
@ -491,7 +490,7 @@ 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
|
||||
\emph{smaller} set to the representative of the \emph{larger} set
|
||||
(or if the sets are of equal size,
|
||||
we can make an arbitrary choice).
|
||||
Using this strategy, the length of any chain
|
||||
|
|
|
@ -20,7 +20,7 @@ on the special properties of the graphs.
|
|||
\index{topological sorting}
|
||||
\index{cycle}
|
||||
|
||||
A \key{topological sort} is a ordering
|
||||
A \key{topological sort} is an ordering
|
||||
of the nodes of a directed graph
|
||||
such that if there is a path from node $a$ to node $b$,
|
||||
then node $a$ appears before node $b$ in the ordering.
|
||||
|
@ -67,8 +67,8 @@ $[4,1,5,2,3,6]$:
|
|||
An acyclic graph always has a topological sort.
|
||||
However, if the graph contains a cycle,
|
||||
it is not possible to form a topological sort,
|
||||
because no node in the cycle can appear
|
||||
before the other nodes in the cycle.
|
||||
because no node of the cycle can appear
|
||||
before the other nodes of the cycle in the ordering.
|
||||
It turns out that depth-first search can be used
|
||||
to both check if a directed graph contains a cycle
|
||||
and, if it does not contain a cycle, to construct a topological sort.
|
||||
|
@ -92,7 +92,7 @@ its state becomes 1.
|
|||
Finally, after all successors of the node have
|
||||
been processed, its state becomes 2.
|
||||
|
||||
If the graph contains a cycle, we will find out this
|
||||
If the graph contains a cycle, we will find this out
|
||||
during the search, because sooner or later
|
||||
we will arrive at a node whose state is 1.
|
||||
In this case, it is not possible to construct a topological sort.
|
||||
|
@ -200,7 +200,7 @@ $[4,5,1,2,3,6]$:
|
|||
\end{center}
|
||||
|
||||
Note that a topological sort is not unique,
|
||||
but there can be several topological sorts for a graph.
|
||||
and there can be several topological sorts for a graph.
|
||||
|
||||
\subsubsection{Example 2}
|
||||
|
||||
|
@ -248,7 +248,8 @@ The search proceeds as follows:
|
|||
\end{center}
|
||||
The search reaches node 2 whose state is 1,
|
||||
which means the graph contains a cycle.
|
||||
In this example, the cycle is $2 \rightarrow 3 \rightarrow 5 \rightarrow 2$.
|
||||
In this example, there is a cycle
|
||||
$2 \rightarrow 3 \rightarrow 5 \rightarrow 2$.
|
||||
|
||||
\section{Dynamic programming}
|
||||
|
||||
|
@ -268,7 +269,7 @@ to an ending node:
|
|||
\subsubsection{Counting the number of paths}
|
||||
|
||||
As an example, let us calculate the number of paths
|
||||
from node 4 to node 6 in the following graph:
|
||||
from node 1 to node 6 in the following graph:
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -281,25 +282,30 @@ from node 4 to node 6 in the following graph:
|
|||
|
||||
\path[draw,thick,->,>=latex] (1) -- (2);
|
||||
\path[draw,thick,->,>=latex] (2) -- (3);
|
||||
\path[draw,thick,->,>=latex] (4) -- (1);
|
||||
\path[draw,thick,->,>=latex] (1) -- (4);
|
||||
\path[draw,thick,->,>=latex] (4) -- (5);
|
||||
\path[draw,thick,->,>=latex] (5) -- (2);
|
||||
\path[draw,thick,->,>=latex] (5) -- (3);
|
||||
\path[draw,thick,->,>=latex] (3) -- (6);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
There are a total of three such paths:
|
||||
\begin{itemize}
|
||||
\item $4 \rightarrow 1 \rightarrow 2 \rightarrow 3 \rightarrow 6$
|
||||
\item $4 \rightarrow 5 \rightarrow 2 \rightarrow 3 \rightarrow 6$
|
||||
\item $4 \rightarrow 5 \rightarrow 3 \rightarrow 6$
|
||||
\item $1 \rightarrow 2 \rightarrow 3 \rightarrow 6$
|
||||
\item $1 \rightarrow 4 \rightarrow 5 \rightarrow 2 \rightarrow 3 \rightarrow 6$
|
||||
\item $1 \rightarrow 4 \rightarrow 5 \rightarrow 3 \rightarrow 6$
|
||||
\end{itemize}
|
||||
|
||||
To count the paths,
|
||||
we go through the nodes in a topological sort,
|
||||
and calculate for each node $x$ the number of paths
|
||||
from node 4 to node $x$.
|
||||
Let $p(x)$ denote the number of paths from
|
||||
node 1 to node $x$.
|
||||
As a base case, $p(1)=1$.
|
||||
Then, to calculate other values of $p(x)$,
|
||||
we may use the recursion
|
||||
\[p(x) = p(a_1)+p(a_2)+\cdots+p(a_k)\]
|
||||
where $a_1,a_2,\ldots,a_k$ are the nodes from which there
|
||||
is an edge to $x$.
|
||||
Since the graph is acyclic, the values of $p(x)$
|
||||
can be calculated in the order of a topological sort.
|
||||
A topological sort for the above graph is as follows:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -319,7 +325,6 @@ A topological sort for the above graph is as follows:
|
|||
\path[draw,thick,->,>=latex] (3) -- (6);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
Hence, the numbers of paths are as follows:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -332,7 +337,7 @@ Hence, the numbers of paths are as follows:
|
|||
|
||||
\path[draw,thick,->,>=latex] (1) -- (2);
|
||||
\path[draw,thick,->,>=latex] (2) -- (3);
|
||||
\path[draw,thick,->,>=latex] (4) -- (1);
|
||||
\path[draw,thick,->,>=latex] (1) -- (4);
|
||||
\path[draw,thick,->,>=latex] (4) -- (5);
|
||||
\path[draw,thick,->,>=latex] (5) -- (2);
|
||||
\path[draw,thick,->,>=latex] (5) -- (3);
|
||||
|
@ -347,18 +352,18 @@ Hence, the numbers of paths are as follows:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
For example, since there are two paths
|
||||
from node 4 to node 2 and
|
||||
there is one path from node 4 to node 5,
|
||||
we can conclude that there are three
|
||||
paths from node 4 to node 3.
|
||||
For example, to calculate the value of $p(3)$,
|
||||
we may use the formula $p(2)+p(5)$,
|
||||
because there are edges from nodes 2 and 5
|
||||
to node 3.
|
||||
Since $p(2)=2$ and $p(5)=1$, we conclude that $p(3)=3$.
|
||||
|
||||
\subsubsection{Extending Dijkstra's algorithm}
|
||||
|
||||
\index{Dijkstra's algorithm}
|
||||
|
||||
A by-product of Dijkstra's algorithm is a directed, acyclic
|
||||
graph that indicates for each node in the original graph
|
||||
graph that indicates for each node of the original graph
|
||||
the possible ways to reach the node using a shortest path
|
||||
from the starting node.
|
||||
Dynamic programming can be applied to that graph.
|
||||
|
@ -470,7 +475,7 @@ the graph is as follows:
|
|||
|
||||
Using this representation,
|
||||
the shortest path from node 0 to node $x$
|
||||
corresponds to a solution with minimum number of coins,
|
||||
corresponds to a solution with the minimum number of coins,
|
||||
and the total number of paths from node 0 to node $x$
|
||||
equals the total number of solutions.
|
||||
|
||||
|
@ -480,8 +485,9 @@ equals the total number of solutions.
|
|||
\index{functional graph}
|
||||
|
||||
For the rest of the chapter,
|
||||
we will concentrate on \key{successor graphs}
|
||||
where the outdegree of each node is 1, i.e.,
|
||||
we will focus on \key{successor graphs}.
|
||||
In those graphs,
|
||||
the outdegree of each node is 1, i.e.,
|
||||
exactly one edge starts at each node.
|
||||
A successor graph consists of one or more
|
||||
components, each of which contains
|
||||
|
@ -491,11 +497,10 @@ Successor graphs are sometimes called
|
|||
\key{functional graphs}.
|
||||
The reason for this is that any successor graph
|
||||
corresponds to a function $f$ that defines
|
||||
the edges in the graph.
|
||||
The parameter for the function is a node in the graph,
|
||||
and the function gives the successor of the node.
|
||||
the edges of the graph.
|
||||
The parameter for the function is a node of the graph,
|
||||
and the function gives the successor of that node.
|
||||
|
||||
\begin{samepage}
|
||||
For example, the function
|
||||
\begin{center}
|
||||
\begin{tabular}{r|rrrrrrrrr}
|
||||
|
@ -504,7 +509,6 @@ $x$ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
|
|||
$f(x)$ & 3 & 5 & 7 & 6 & 2 & 2 & 1 & 6 & 3 \\
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\end{samepage}
|
||||
defines the following graph:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -530,8 +534,8 @@ defines the following graph:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
Since each node in a successor graph has a
|
||||
unique successor, we can define a function $f(x,k)$
|
||||
Since each node of a successor graph has a
|
||||
unique successor, we can also define a function $f(x,k)$
|
||||
that gives the node that we will reach if
|
||||
we begin at node $x$ and walk $k$ steps forward.
|
||||
For example, in the above graph $f(4,6)=2$,
|
||||
|
@ -574,7 +578,7 @@ we can use the following recursion:
|
|||
\end{cases}
|
||||
\end{equation*}
|
||||
|
||||
Precalculating values $f(x,k)$ takes $O(n \log u)$ time,
|
||||
Precalculating the values takes $O(n \log u)$ time,
|
||||
because $O(\log u)$ values are calculated for each node.
|
||||
In the above graph, the first values are as follows:
|
||||
|
||||
|
@ -610,7 +614,7 @@ takes $O(\log k)$ time.
|
|||
|
||||
Consider a successor graph that only contains
|
||||
a path that ends in a cycle.
|
||||
There are two interesting questions:
|
||||
We may ask the following questions:
|
||||
if we begin our walk at the starting node,
|
||||
what is the first node in the cycle
|
||||
and how many nodes does the cycle contain?
|
||||
|
|
|
@ -516,8 +516,8 @@ their values will be determined
|
|||
according to the values in the component,
|
||||
and if they already have values,
|
||||
they remain unchanged.
|
||||
The process continues until all variables
|
||||
have been assigned values.
|
||||
The process continues until each variable
|
||||
has been assigned a value.
|
||||
|
||||
The component graph for the formula $L_1$ is as follows:
|
||||
\begin{center}
|
||||
|
|
|
@ -52,16 +52,15 @@ and $f(5,2)=0$.
|
|||
An easy way to calculate the value of $f(x,k)$
|
||||
is to perform a sequence of $k$ moves in the tree.
|
||||
However, the time complexity of this method
|
||||
is $O(n)$, because the tree may contain
|
||||
a chain of $O(n)$ nodes.
|
||||
is $O(k)$, which may be slow, because a tree of $n$
|
||||
nodes may have a chain of $n$ nodes.
|
||||
|
||||
Fortunately, it turns out that
|
||||
using a technique similar to that
|
||||
Fortunately, using a technique similar to that
|
||||
used in Chapter 16.3, any value of $f(x,k)$
|
||||
can be efficiently calculated in $O(\log k)$ time
|
||||
after preprocessing.
|
||||
The idea is to precalculate all values $f(x,k)$
|
||||
where $k$ is a power of two.
|
||||
where $k \le n$ is a power of two.
|
||||
For example, the values for the above tree
|
||||
are as follows:
|
||||
|
||||
|
@ -77,7 +76,7 @@ $\cdots$ \\
|
|||
\end{center}
|
||||
|
||||
The preprocessing takes $O(n \log n)$ time,
|
||||
because each node can have at most $n$ ancestors.
|
||||
because $O(\log n)$ values are calculated for each node.
|
||||
After this, any value of $f(x,k)$ can be calculated
|
||||
in $O(\log k)$ time by representing $k$
|
||||
as a sum where each term is a power of two.
|
||||
|
@ -185,10 +184,10 @@ Hence, the corresponding tree traversal array is as follows:
|
|||
\subsubsection{Subtree queries}
|
||||
|
||||
Each subtree of a tree corresponds to a subarray
|
||||
in the tree traversal array such that
|
||||
the first element in the subarray is the root node.
|
||||
of the tree traversal array such that
|
||||
the first element of the subarray is the root node.
|
||||
For example, the following subarray contains the
|
||||
nodes in the subtree of node $4$:
|
||||
nodes of the subtree of node $4$:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.7]
|
||||
\fill[color=lightgray] (4,0) rectangle (8,1);
|
||||
|
@ -382,7 +381,7 @@ can be found as follows:
|
|||
|
||||
To answer the queries efficiently,
|
||||
it suffices to store the values of the
|
||||
nodes in a binary indexed tree or segment tree.
|
||||
nodes in a binary indexed or segment tree.
|
||||
After this, we can both update a value
|
||||
and calculate the sum of values in $O(\log n)$ time.
|
||||
|
||||
|
@ -390,9 +389,9 @@ and calculate the sum of values in $O(\log n)$ time.
|
|||
|
||||
Using a tree traversal array, we can also efficiently
|
||||
calculate sums of values on
|
||||
paths from the root node to any other
|
||||
node in the tree.
|
||||
Let us next consider a problem where our task
|
||||
paths from the root node to any
|
||||
node of the tree.
|
||||
Let us consider a problem where our task
|
||||
is to support the following queries:
|
||||
\begin{itemize}
|
||||
\item change the value of a node
|
||||
|
@ -553,7 +552,7 @@ Thus, to support both the operations,
|
|||
we should be able to increase all values
|
||||
in a range and retrieve a single value.
|
||||
This can be done in $O(\log n)$ time
|
||||
using a binary indexed tree
|
||||
using a binary indexed
|
||||
or segment tree (see Chapter 9.4).
|
||||
|
||||
\section{Lowest common ancestor}
|
||||
|
@ -561,11 +560,11 @@ or segment tree (see Chapter 9.4).
|
|||
\index{lowest common ancestor}
|
||||
|
||||
The \key{lowest common ancestor}
|
||||
of two nodes in the tree is the lowest node
|
||||
of two nodes of a rooted tree is the lowest node
|
||||
whose subtree contains both the nodes.
|
||||
A typical problem is to efficiently process
|
||||
queries that ask to find the lowest
|
||||
common ancestor of given two nodes.
|
||||
common ancestor of two nodes.
|
||||
|
||||
For example, in the following tree,
|
||||
the lowest common ancestor of nodes 5 and 8
|
||||
|
@ -605,13 +604,13 @@ Using this, we can divide the problem of
|
|||
finding the lowest common ancestor into two parts.
|
||||
|
||||
We use two pointers that initially point to the
|
||||
two nodes for which we should find the
|
||||
lowest common ancestor.
|
||||
two nodes whose lowest common ancestor we should find.
|
||||
First, we move one of the pointers upwards
|
||||
so that both nodes are at the same level in the tree.
|
||||
so that both pointers point to nodes at the same level.
|
||||
|
||||
In the example case, we move from node 8 to node 6,
|
||||
after which both nodes are at the same level:
|
||||
In the example case, we move the second pointer one
|
||||
level up so that it points to node 6
|
||||
which is at the same level with node 5:
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -638,7 +637,8 @@ after which both nodes are at the same level:
|
|||
After this, we determine the minimum number of steps
|
||||
needed to move both pointers upwards so that
|
||||
they will point to the same node.
|
||||
This node is the lowest common ancestor of the nodes.
|
||||
The node to which the pointers point after this
|
||||
is the lowest common ancestor.
|
||||
|
||||
In the example case, it suffices to move both pointers
|
||||
one step upwards to node 2,
|
||||
|
@ -670,12 +670,12 @@ which is the lowest common ancestor:
|
|||
Since both parts of the algorithm can be performed in
|
||||
$O(\log n)$ time using precomputed information,
|
||||
we can find the lowest common ancestor of any two
|
||||
nodes in $O(\log n)$ time using this technique.
|
||||
nodes in $O(\log n)$ time.
|
||||
|
||||
\subsubsection{Method 2}
|
||||
|
||||
Another way to solve the problem is based on
|
||||
a tree traversal array\footnote{This lowest common ancestor algorithm is based on \cite{ben00}.
|
||||
a tree traversal array\footnote{This lowest common ancestor algorithm was presented in \cite{ben00}.
|
||||
This technique is sometimes called the \index{Euler tour technique}
|
||||
\key{Euler tour technique} \cite{tar84}.}.
|
||||
Once again, the idea is to traverse the nodes
|
||||
|
@ -716,7 +716,7 @@ using a depth-first search:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
However, we use a bit different tree
|
||||
However, we use a different tree
|
||||
traversal array than before:
|
||||
we add each node to the array \emph{always}
|
||||
when the depth-first search walks through the node,
|
||||
|
@ -792,8 +792,8 @@ The following array corresponds to the above tree:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
Using this array, we can find the lowest common ancestor
|
||||
of nodes $a$ and $b$ by finding the node with lowest level
|
||||
Now we can find the lowest common ancestor
|
||||
of nodes $a$ and $b$ by finding the node with the \emph{lowest} level
|
||||
between nodes $a$ and $b$ in the array.
|
||||
For example, the lowest common ancestor of nodes $5$ and $8$
|
||||
can be found as follows:
|
||||
|
@ -881,8 +881,8 @@ after an $O(n \log n)$ time preprocessing.
|
|||
\subsubsection{Distances of nodes}
|
||||
|
||||
Finally, let us consider the problem of
|
||||
finding the distance between
|
||||
two nodes in the tree, which equals
|
||||
calculating the distance between
|
||||
two nodes of a tree, which equals
|
||||
the length of the path between them.
|
||||
It turns out that this problem reduces to
|
||||
finding the lowest common ancestor of the nodes.
|
||||
|
@ -892,7 +892,7 @@ After this, the distance between nodes $a$ and $b$
|
|||
can be calculated using the formula
|
||||
\[d(a)+d(b)-2 \cdot d(c),\]
|
||||
where $c$ is the lowest common ancestor of $a$ and $b$
|
||||
and $d(s)$ denotes the distance from the root node
|
||||
and $d(s)$ denotes the distance from the root
|
||||
to node $s$.
|
||||
For example, in the tree
|
||||
|
||||
|
@ -1149,11 +1149,11 @@ algorithms discussed earlier in this chapter.
|
|||
|
||||
The algorithm is given as input a set of pairs of nodes,
|
||||
and it determines for each such pair the
|
||||
lowest common ancestor.
|
||||
lowest common ancestor of the nodes.
|
||||
The algorithm performs a depth-first tree traversal
|
||||
and maintains disjoint sets of nodes.
|
||||
Initially, each node belongs to a separate set.
|
||||
For each set, we also maintain the highest node in the
|
||||
For each set, we also store the highest node in the
|
||||
tree that belongs to the set.
|
||||
|
||||
When the algorithm visits a node $x$,
|
||||
|
@ -1164,11 +1164,11 @@ If $y$ has already been visited,
|
|||
the algorithm reports that the
|
||||
lowest common ancestor of $x$ and $y$
|
||||
is the highest node in the set of $y$.
|
||||
Then, after processing the subtree of $x$,
|
||||
the algorithm combines the sets of $x$ and its parent.
|
||||
Then, after processing node $x$,
|
||||
the algorithm joins the sets of $x$ and its parent.
|
||||
|
||||
For example, assume that we would like the lowest
|
||||
common ancestor of node pairs $(5,8)$
|
||||
For example, assume that we wish to find the lowest
|
||||
common ancestors of node pairs $(5,8)$
|
||||
and $(2,7)$ in the following tree:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.85]
|
||||
|
|
|
@ -7,16 +7,17 @@ goes through each edge exactly once.
|
|||
\item A \key{Hamiltonian path} is a path
|
||||
that visits each node exactly once.
|
||||
\end{itemize}
|
||||
|
||||
While Eulerian and Hamiltonian paths look like
|
||||
similar concepts at first glance,
|
||||
the computational problems related to them
|
||||
are very different.
|
||||
It turns out that there is a simple rule that
|
||||
determines whether a graph contains an Eulerian path
|
||||
determines whether a graph contains an Eulerian path,
|
||||
and there is also an efficient algorithm to
|
||||
find such a path if it exists.
|
||||
On the contrary, checking the existence of a Hamiltonian path is a NP-hard
|
||||
problem and no efficient algorithm is known for solving the problem.
|
||||
problem, and no efficient algorithm is known for solving the problem.
|
||||
|
||||
\section{Eulerian paths}
|
||||
|
||||
|
@ -25,7 +26,7 @@ problem and no efficient algorithm is known for solving the problem.
|
|||
An \key{Eulerian path}\footnote{L. Euler studied such paths in 1736
|
||||
when he solved the famous Königsberg bridge problem.
|
||||
This was the birth of graph theory.} is a path
|
||||
that goes exactly once through each edge in the graph.
|
||||
that goes exactly once through each edge of the graph.
|
||||
For example, the graph
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -116,7 +117,7 @@ has an Eulerian circuit that starts and ends at node 1:
|
|||
\subsubsection{Existence}
|
||||
|
||||
The existence of Eulerian paths and circuits
|
||||
depends on the degrees of the nodes in the graph.
|
||||
depends on the degrees of the nodes of the graph.
|
||||
First, an undirected graph has an Eulerian path if all the edges
|
||||
belong to the same connected component and
|
||||
\begin{itemize}
|
||||
|
@ -125,7 +126,7 @@ belong to the same connected component and
|
|||
and the degree of all other nodes is even.
|
||||
\end{itemize}
|
||||
|
||||
In the first case, each Eulerian path in the graph
|
||||
In the first case, each Eulerian path of the graph
|
||||
is also an Eulerian circuit.
|
||||
In the second case, the odd-degree nodes are the starting
|
||||
and ending nodes of an Eulerian path which is not an Eulerian circuit.
|
||||
|
@ -165,10 +166,10 @@ connected component and
|
|||
\item in each node, the indegree equals the outdegree, \emph{or}
|
||||
\item in one node, the indegree is one larger than the outdegree,
|
||||
in another node, the outdegree is one larger than the indegree,
|
||||
and all other nodes, the indegree equals the outdegree.
|
||||
and in all other nodes, the indegree equals the outdegree.
|
||||
\end{itemize}
|
||||
|
||||
In the first case, each Eulerian path in the graph
|
||||
In the first case, each Eulerian path of the graph
|
||||
is also an Eulerian circuit,
|
||||
and in the second case, the graph contains an Eulerian path
|
||||
that begins at the node whose outdegree is larger
|
||||
|
@ -235,7 +236,7 @@ an Eulerian circuit; otherwise Hierholzer's
|
|||
algorithm cannot find it.
|
||||
|
||||
First, the algorithm constructs a circuit that contains
|
||||
some (not necessarily all) of the edges in the graph.
|
||||
some (not necessarily all) of the edges of the graph.
|
||||
After this, the algorithm extends the circuit
|
||||
step by step by adding subcircuits to it.
|
||||
The process continues until all edges have been added
|
||||
|
@ -260,7 +261,7 @@ we add the extra edge between the two
|
|||
odd-degree nodes.
|
||||
|
||||
Next we will see how Hierholzer's algorithm
|
||||
constructs an Eulerian circuit in an undirected graph.
|
||||
constructs an Eulerian circuit for an undirected graph.
|
||||
|
||||
\subsubsection{Example}
|
||||
|
||||
|
@ -401,7 +402,7 @@ so we have successfully constructed an Eulerian circuit.
|
|||
A \key{Hamiltonian path}
|
||||
%\footnote{W. R. Hamilton (1805--1865) was an Irish mathematician.}
|
||||
is a path
|
||||
that visits each node in the graph exactly once.
|
||||
that visits each node of the graph exactly once.
|
||||
For example, the graph
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -474,9 +475,9 @@ that begins and ends at node 1:
|
|||
\subsubsection{Existence}
|
||||
|
||||
No efficient method is known for testing if a graph
|
||||
contains a Hamiltonian path, but the problem is NP-hard.
|
||||
Still, in some special cases we can be certain
|
||||
that the graph contains a Hamiltonian path.
|
||||
contains a Hamiltonian path, and the problem is NP-hard.
|
||||
Still, in some special cases, we can be certain
|
||||
that a graph contains a Hamiltonian path.
|
||||
|
||||
A simple observation is that if the graph is complete,
|
||||
i.e., there is an edge between all pairs of nodes,
|
||||
|
@ -507,7 +508,7 @@ the more possibilities there is to construct a Hamiltonian path.
|
|||
|
||||
Since there is no efficient way to check if a Hamiltonian
|
||||
path exists, it is clear that there is also no method
|
||||
for constructing the path efficiently, because otherwise
|
||||
to efficiently construct the path, because otherwise
|
||||
we could just try to construct the path and see
|
||||
whether it exists.
|
||||
|
||||
|
@ -523,7 +524,7 @@ The idea is to define a function $f(s,x)$,
|
|||
where $s$ is a subset of nodes and $x$
|
||||
is one of the nodes in the subset.
|
||||
The function indicates whether there is a Hamiltonian path
|
||||
that visits the nodes in $s$ and ends at node $x$.
|
||||
that visits the nodes of $s$ and ends at node $x$.
|
||||
It is possible to implement this solution in $O(2^n n^2)$ time.
|
||||
|
||||
\section{De Bruijn sequences}
|
||||
|
@ -547,8 +548,8 @@ combinations of three bits:
|
|||
|
||||
It turns out that each De Bruijn sequence
|
||||
corresponds to an Eulerian path in a graph.
|
||||
The idea is to construct the graph so that
|
||||
each node contains a combination of $n-1$ characters
|
||||
The idea is to construct the graph where
|
||||
each node contains a string of $n-1$ characters
|
||||
and each edge adds one character to the string.
|
||||
The following graph corresponds to the above example:
|
||||
|
||||
|
@ -575,7 +576,7 @@ The following graph corresponds to the above example:
|
|||
An Eulerian path in this graph corresponds to a string
|
||||
that contains all strings of length $n$.
|
||||
The string contains the characters of the starting node
|
||||
and all characters in the edges.
|
||||
and all characters of the edges.
|
||||
The starting node has $n-1$ characters
|
||||
and there are $k^n$ characters in the edges,
|
||||
so the length of the string is $k^n+n-1$.
|
||||
|
@ -588,9 +589,9 @@ A \key{knight's tour} is a sequence of moves
|
|||
of a knight on an $n \times n$ chessboard
|
||||
following the rules of chess such that the knight
|
||||
visits each square exactly once.
|
||||
A tour is \emph{closed} if the knight finally
|
||||
returns to the starting square and
|
||||
otherwise it is \emph{open}.
|
||||
A knight's tour is called a \emph{closed} tour
|
||||
if the knight finally returns to the starting square and
|
||||
otherwise it is called an \emph{open} tour.
|
||||
|
||||
For example, here is an open knight's tour on a $5 \times 5$ board:
|
||||
|
||||
|
@ -626,13 +627,13 @@ For example, here is an open knight's tour on a $5 \times 5$ board:
|
|||
\end{center}
|
||||
|
||||
A knight's tour corresponds to a Hamiltonian path in a graph
|
||||
whose nodes represent the squares of the board
|
||||
whose nodes represent the squares of the board,
|
||||
and two nodes are connected with an edge if a knight
|
||||
can move between the squares according to the rules of chess.
|
||||
|
||||
A natural way to construct a knight's tour is to use backtracking.
|
||||
The search can be made more efficient by using
|
||||
\key{heuristics} that attempt to guide the knight so that
|
||||
\emph{heuristics} that attempt to guide the knight so that
|
||||
a complete tour will be found quickly.
|
||||
|
||||
\subsubsection{Warnsdorf's rule}
|
||||
|
@ -651,7 +652,7 @@ The idea is to always move the knight so that it ends up
|
|||
in a square where the number of possible moves is as
|
||||
\emph{small} as possible.
|
||||
|
||||
For example, in the following situation there are five
|
||||
For example, in the following situation, there are five
|
||||
possible squares to which the knight can move:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.7]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
\chapter{Flows and cuts}
|
||||
|
||||
In this chapter, we will focus on the following
|
||||
In this chapter, we focus on the following
|
||||
two problems:
|
||||
|
||||
\begin{itemize}
|
||||
|
@ -14,8 +14,8 @@ that separates two nodes of the graph?
|
|||
|
||||
The input for both these problems is a directed,
|
||||
weighted graph that contains two special nodes:
|
||||
the \key{source} is a node with no incoming edges,
|
||||
and the \key{sink} is a node with no outgoing edges.
|
||||
the \emph{source} is a node with no incoming edges,
|
||||
and the \emph{sink} is a node with no outgoing edges.
|
||||
|
||||
As an example, we will use the following graph
|
||||
where node 1 is the source and node 6
|
||||
|
@ -55,7 +55,7 @@ In each intermediate node,
|
|||
the incoming and outgoing
|
||||
flow has to be equal.
|
||||
|
||||
For example, the size of the maximum flow
|
||||
For example, the maximum size of a flow
|
||||
in the example graph is 7.
|
||||
The following picture shows how we can
|
||||
route the flow:
|
||||
|
@ -102,7 +102,7 @@ to the sink after the removal
|
|||
and the total weight of the removed edges
|
||||
is minimum.
|
||||
|
||||
The size of the minimum cut in the example graph is 7.
|
||||
The minimum size of a cut in the example graph is 7.
|
||||
It suffices to remove the edges $2 \rightarrow 3$
|
||||
and $4 \rightarrow 5$:
|
||||
|
||||
|
@ -140,11 +140,12 @@ way to remove edges from the graph such that
|
|||
their total weight would be less than $7$.
|
||||
\\\\
|
||||
It is not a coincidence that
|
||||
both the size of the maximum flow and
|
||||
the size of the minimum cut is 7 in the above example.
|
||||
It turns out that the size of the maximum flow
|
||||
and the minimum cut is
|
||||
\emph{always} the same,
|
||||
the maximum size of a flow
|
||||
and the minimum size of a cut
|
||||
are the same in the above example.
|
||||
It turns out that a maximum flow
|
||||
and a minimum cut are
|
||||
\emph{always} equally large,
|
||||
so the concepts are two sides of the same coin.
|
||||
|
||||
Next we will discuss the Ford–Fulkerson
|
||||
|
@ -160,10 +161,10 @@ The algorithm also helps us to understand
|
|||
The \key{Ford–Fulkerson algorithm} \cite{for56} finds
|
||||
the maximum flow in a graph.
|
||||
The algorithm begins with an empty flow,
|
||||
and at each step finds a path in the graph
|
||||
that generates more flow.
|
||||
and at each step finds a path from the source
|
||||
to the sink that generates more flow.
|
||||
Finally, when the algorithm cannot increase the flow
|
||||
anymore, it terminates and the maximum flow has been found.
|
||||
anymore, the maximum flow has been found.
|
||||
|
||||
The algorithm uses a special representation
|
||||
of the graph where each original edge has a reverse
|
||||
|
@ -293,7 +294,7 @@ and the new graph is as follows:
|
|||
|
||||
The idea is that increasing the flow decreases the amount of
|
||||
flow that can go through the edges in the future.
|
||||
On the other hand, it is possible to modify the
|
||||
On the other hand, it is possible to cancel
|
||||
flow later using the reverse edges of the graph
|
||||
if it turns out that
|
||||
it would be beneficial to route the flow in another way.
|
||||
|
@ -435,7 +436,7 @@ chooses each path so that the number of edges
|
|||
on the path is as small as possible.
|
||||
This can be done by using breadth-first search
|
||||
instead of depth-first search for finding paths.
|
||||
It turns out that this guarantees that
|
||||
It can be proven that this guarantees that
|
||||
the flow increases quickly, and the time complexity
|
||||
of the algorithm is $O(m^2 n)$.
|
||||
|
||||
|
@ -445,8 +446,8 @@ The \key{scaling algorithm} \cite{ahu91} uses depth-first
|
|||
search to find paths where each edge weight is
|
||||
at least a threshold value.
|
||||
Initially, the threshold value is
|
||||
the sum of capacities of the edges that
|
||||
start at the source.
|
||||
some large number, for example the sum of all
|
||||
edge weights of the graph.
|
||||
Always when a path cannot be found,
|
||||
the threshold value is divided by 2.
|
||||
The time complexity of the algorithm is $O(m^2 \log c)$,
|
||||
|
@ -463,7 +464,7 @@ that typically appear in programming contests.
|
|||
|
||||
It turns out that once the Ford–Fulkerson algorithm
|
||||
has found a maximum flow,
|
||||
it has also found a minimum cut.
|
||||
it has also determined a minimum cut.
|
||||
Let $A$ be the set of nodes
|
||||
that can be reached from the source
|
||||
using positive-weight edges.
|
||||
|
@ -509,14 +510,14 @@ Why is the flow produced by the algorithm maximum
|
|||
and why is the cut minimum?
|
||||
The reason is that a graph cannot
|
||||
contain a flow whose size is larger
|
||||
than the weight of any cut in the graph.
|
||||
than the weight of any cut of the graph.
|
||||
Hence, always when a flow and a cut are equally large,
|
||||
they are a maximum flow and a minimum cut.
|
||||
|
||||
Let us consider any cut in the graph
|
||||
Let us consider any cut of the graph
|
||||
such that the source belongs to $A$,
|
||||
the sink belongs to $B$
|
||||
and there are edges between the sets:
|
||||
and there are some edges between the sets:
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -645,8 +646,8 @@ to the sink.
|
|||
In this problem, every node,
|
||||
except for the source and sink,
|
||||
may appear in at most one path.
|
||||
The number of node-disjoint paths is
|
||||
often smaller than the number of
|
||||
The number of node-disjoint paths
|
||||
may be smaller than the number of
|
||||
edge-disjoint paths.
|
||||
|
||||
For example, in the previous graph,
|
||||
|
@ -682,9 +683,9 @@ Since each node can appear in at most one path,
|
|||
we have to limit the flow that goes through the nodes.
|
||||
A standard method for this is to divide each node into
|
||||
two nodes such that the first node has the incoming edges
|
||||
of the original node and the second node has the outgoing
|
||||
edges of the original node.
|
||||
In addition, there is a new edge from the first node
|
||||
of the original node, the second node has the outgoing
|
||||
edges of the original node, and
|
||||
there is a new edge from the first node
|
||||
to the second node.
|
||||
|
||||
In our example, the graph becomes as follows:
|
||||
|
@ -772,7 +773,7 @@ from the source to the sink is 1.
|
|||
\index{maximum matching}
|
||||
|
||||
The \key{maximum matching} problem asks to find
|
||||
a maximum-size set of node pairs in a graph
|
||||
a maximum-size set of node pairs of a graph
|
||||
such that each pair is connected with an edge and
|
||||
each node belongs to at most one pair.
|
||||
|
||||
|
@ -787,10 +788,11 @@ maximum flow problem.
|
|||
|
||||
\subsubsection{Finding maximum matchings}
|
||||
|
||||
The nodes in a bipartite graph can be always
|
||||
The nodes of a bipartite graph can be always
|
||||
divided into two groups such that all edges
|
||||
of the graph go from the left group to the right group.
|
||||
For example, consider the following bipartite graph:
|
||||
For example, in the following bipartite graph,
|
||||
the groups are $\{1,2,3,4\}$ and $\{5,6,7,8\}$.
|
||||
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.60]
|
||||
|
@ -811,8 +813,7 @@ For example, consider the following bipartite graph:
|
|||
\path[draw,thick,-] (4) -- (7);
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
In this graph, the size of a maximum matching is 3:
|
||||
The size of a maximum matching of the graph is 3:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.60]
|
||||
\node[draw, circle] (1) at (2,4.5) {1};
|
||||
|
@ -840,7 +841,7 @@ In this graph, the size of a maximum matching is 3:
|
|||
We can reduce the bipartite maximum matching problem
|
||||
to the maximum flow problem by adding two new nodes
|
||||
to the graph: a source and a sink.
|
||||
In addition, we add edges from the source
|
||||
We also add edges from the source
|
||||
to each left node and from each right node to the sink.
|
||||
After this, the maximum flow of the graph
|
||||
equals the maximum matching of the original graph.
|
||||
|
@ -996,7 +997,7 @@ Next, let $X=\{2,4\}$ which yields $f(X)=\{7\}$:
|
|||
In this case, $|X|=2$ and $|f(X)|=1$,
|
||||
so the condition of Hall's theorem does not hold.
|
||||
This means that it is not possible to form
|
||||
a perfect matching in the graph.
|
||||
a perfect matching for the graph.
|
||||
This result is not surprising, because we already
|
||||
know that the maximum matching of the graph is 3 and not 4.
|
||||
|
||||
|
@ -1115,7 +1116,7 @@ set is as follows:
|
|||
|
||||
\index{path cover}
|
||||
|
||||
A \key{path cover} is a set of paths in a graph
|
||||
A \key{path cover} is a set of paths of a graph
|
||||
such that each node of the graph belongs to at least one path.
|
||||
It turns out that in directed, acyclic graphs,
|
||||
we can reduce the problem of finding a minimum
|
||||
|
@ -1172,19 +1173,20 @@ Note that one of the paths only contains node 2,
|
|||
so it is possible that a path does not contain any edges.
|
||||
|
||||
We can find a minimum node-disjoint path cover
|
||||
by constructing a matching graph where each node
|
||||
by constructing a \emph{matching graph} where each node
|
||||
of the original graph is represented by
|
||||
two nodes: a left node and a right node.
|
||||
There is an edge from a left node to a right node
|
||||
if there is a such an edge in the original graph.
|
||||
In addition, the matching graph contains a source and a sink
|
||||
such that there are edges from the source to all
|
||||
In addition, the matching graph contains a source and a sink,
|
||||
and there are edges from the source to all
|
||||
left nodes and from all right nodes to the sink.
|
||||
|
||||
A maximum matching in the resulting graph corresponds
|
||||
A maximum matching of the resulting graph corresponds
|
||||
to a minimum node-disjoint path cover in
|
||||
the original graph.
|
||||
For example, the following graph contains
|
||||
For example, the following matching graph
|
||||
for the above graph contains
|
||||
a maximum matching of size 4:
|
||||
|
||||
\begin{center}
|
||||
|
@ -1252,7 +1254,7 @@ A \key{general path cover} is a path cover
|
|||
where a node can belong to more than one path.
|
||||
A minimum general path cover may be smaller
|
||||
than a minimum node-disjoint path cover,
|
||||
because a node can used multiple times in paths.
|
||||
because a node can be used multiple times in paths.
|
||||
Consider again the following graph:
|
||||
\begin{center}
|
||||
\begin{tikzpicture}[scale=0.9]
|
||||
|
@ -1273,7 +1275,7 @@ Consider again the following graph:
|
|||
\end{tikzpicture}
|
||||
\end{center}
|
||||
|
||||
The minimum general path cover in this graph
|
||||
The minimum general path cover of this graph
|
||||
consists of two paths.
|
||||
For example, the first path may be as follows:
|
||||
\begin{center}
|
||||
|
|
Loading…
Reference in New Issue