2016-12-28 23:54:51 +01:00
|
|
|
\chapter{Graph search}
|
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
This chapter introduces two fundamental
|
|
|
|
graph algorithms:
|
|
|
|
depth-first search and breadth-first search.
|
|
|
|
Both algorithms are given a starting
|
|
|
|
node in the graph,
|
|
|
|
and they visit all nodes that can be reached
|
|
|
|
from the starting node.
|
|
|
|
The difference in the algorithms is the order
|
|
|
|
in which they visit the nodes.
|
|
|
|
|
|
|
|
\section{Depth-first search}
|
|
|
|
|
|
|
|
\index{depth-first search}
|
|
|
|
|
|
|
|
\key{Depth-first search} (DFS)
|
|
|
|
is a straightforward graph search 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.
|
|
|
|
|
|
|
|
Depth-first search always follows a single
|
|
|
|
path in the graph as long as it finds
|
|
|
|
new nodes.
|
|
|
|
After this, it returns back to previous
|
|
|
|
nodes and begins to explore other parts of the graph.
|
|
|
|
The algorithm keeps track of visited nodes,
|
|
|
|
so that it processes each node only once.
|
|
|
|
|
|
|
|
\subsubsection*{Example}
|
|
|
|
|
|
|
|
Let's consider how depth-first search processes
|
|
|
|
the following graph:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle] (3) at (5,4) {$3$};
|
|
|
|
\node[draw, circle] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle] (5) at (3,3) {$5$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (3) -- (5);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
The algorithm can begin at any node in the graph,
|
|
|
|
but we will now assume that it begins
|
|
|
|
at node 1.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
The search first proceeds to node 2:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle] (3) at (5,4) {$3$};
|
|
|
|
\node[draw, circle] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle] (5) at (3,3) {$5$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (3) -- (5);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (2);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
After this, nodes 3 and 5 will be visited:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle,fill=lightgray] (3) at (5,4) {$3$};
|
|
|
|
\node[draw, circle] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle,fill=lightgray] (5) at (3,3) {$5$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (3) -- (5);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (2) -- (3);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (3) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
The neighbors of node 5 are 2 and 3,
|
|
|
|
but the search has already visited both of them,
|
|
|
|
so it's time to return back.
|
|
|
|
Also the neighbors of nodes 3 and 2
|
|
|
|
have been visited, so we'll next proceed
|
|
|
|
from node 1 to node 4:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle,fill=lightgray] (3) at (5,4) {$3$};
|
|
|
|
\node[draw, circle,fill=lightgray] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle,fill=lightgray] (5) at (3,3) {$5$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (3) -- (5);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (4);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
After this, the search terminates because it has visited
|
|
|
|
all nodes.
|
|
|
|
|
|
|
|
The time complexity of depth-first search is $O(n+m)$
|
|
|
|
where $n$ is the number of nodes and $m$ is the
|
|
|
|
number of edges,
|
|
|
|
because the algorithm processes each node and edge once.
|
|
|
|
|
|
|
|
\subsubsection*{Implementation}
|
|
|
|
|
|
|
|
Depth-first search can be conveniently
|
|
|
|
implemented using recursion.
|
|
|
|
The following function \texttt{dfs} begins
|
|
|
|
a depth-first search at a given node.
|
|
|
|
The function assumes that the graph is
|
|
|
|
stored as adjacency lists in array
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
vector<int> v[N];
|
|
|
|
\end{lstlisting}
|
2017-01-07 17:30:14 +01:00
|
|
|
and also maintains an array
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int z[N];
|
|
|
|
\end{lstlisting}
|
2017-01-07 17:30:14 +01:00
|
|
|
that keeps track of the visited nodes.
|
|
|
|
Initially, each array value is 0,
|
|
|
|
and when the search arrives at node $s$,
|
|
|
|
the value of \texttt{z}[$s$] becomes 1.
|
|
|
|
The function can be implemented as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
2017-01-07 17:30:14 +01:00
|
|
|
void dfs(int s) {
|
2016-12-28 23:54:51 +01:00
|
|
|
if (z[s]) return;
|
|
|
|
z[s] = 1;
|
2017-01-07 17:30:14 +01:00
|
|
|
// process node s
|
2016-12-28 23:54:51 +01:00
|
|
|
for (auto u: v[s]) {
|
2017-01-07 17:30:14 +01:00
|
|
|
dfs(u);
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
\section{Breadth-first search}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
\index{breadth-first search}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
\key{Breadth-first search} (BFS) visits the nodes
|
|
|
|
in increasing order of their distance
|
|
|
|
from the starting node.
|
|
|
|
Thus, we can calculate the distance
|
|
|
|
from the starting node to all other
|
|
|
|
nodes using breadth-first search.
|
|
|
|
However, breadth-first search is more difficult
|
|
|
|
to implement than depth-first search.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
Breadth-first search goes through the nodes
|
|
|
|
one level after another.
|
|
|
|
First the search explores the nodes whose
|
|
|
|
distance from the starting node is 1,
|
|
|
|
then the nodes whose distance is 2, and so on.
|
|
|
|
This process continues until all nodes
|
|
|
|
have been visited.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
\subsubsection*{Example}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
Let's consider how the algorithm processes
|
|
|
|
the following graph:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle] (3) at (5,5) {$3$};
|
|
|
|
\node[draw, circle] (4) at (1,3) {$4$};
|
|
|
|
\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);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (6);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
Assume again that the search begins at node 1.
|
|
|
|
First, we process all nodes that can be reached
|
|
|
|
from node 1 using a single edge:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle] (3) at (5,5) {$3$};
|
|
|
|
\node[draw, circle,fill=lightgray] (4) at (1,3) {$4$};
|
|
|
|
\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);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (6);
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (4);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
After this, we procees to nodes 3 and 5:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle,fill=lightgray] (3) at (5,5) {$3$};
|
|
|
|
\node[draw, circle,fill=lightgray] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle,fill=lightgray] (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);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (6);
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (2) -- (3);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (2) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
Finally, we visit node 6:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=lightgray] (1) at (1,5) {$1$};
|
|
|
|
\node[draw, circle,fill=lightgray] (2) at (3,5) {$2$};
|
|
|
|
\node[draw, circle,fill=lightgray] (3) at (5,5) {$3$};
|
|
|
|
\node[draw, circle,fill=lightgray] (4) at (1,3) {$4$};
|
|
|
|
\node[draw, circle,fill=lightgray] (5) at (3,3) {$5$};
|
|
|
|
\node[draw, circle,fill=lightgray] (6) at (5,3) {$6$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (6);
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (3) -- (6);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (5) -- (6);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 17:30:14 +01:00
|
|
|
Now we have calculated the distances
|
|
|
|
from the starting node to all nodes in the graph.
|
|
|
|
The distances are as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{tabular}{ll}
|
|
|
|
\\
|
2017-01-07 17:30:14 +01:00
|
|
|
node & distance \\
|
2016-12-28 23:54:51 +01:00
|
|
|
\hline
|
|
|
|
1 & 0 \\
|
|
|
|
2 & 1 \\
|
|
|
|
3 & 2 \\
|
|
|
|
4 & 1 \\
|
|
|
|
5 & 2 \\
|
|
|
|
6 & 3 \\
|
|
|
|
\\
|
|
|
|
\end{tabular}
|
|
|
|
|
2017-01-07 17:30:14 +01:00
|
|
|
Like in depth-first search,
|
|
|
|
the time complexity of breadth-first search
|
|
|
|
is $O(n+m)$ where $n$ is the number of nodes
|
|
|
|
and $m$ is the number of edges.
|
|
|
|
|
|
|
|
\subsubsection*{Implementation}
|
|
|
|
|
|
|
|
Breadth-first search is more difficult
|
|
|
|
to implement than depth-first search
|
|
|
|
because the algorithm visits nodes
|
|
|
|
in different parts in the graph.
|
|
|
|
A typical implementation is to maintain
|
|
|
|
a queue of nodes to be processed.
|
|
|
|
At each step, the next node in the queue
|
|
|
|
will be processed.
|
|
|
|
|
|
|
|
The following code begins a breadth-first
|
|
|
|
search at node $x$.
|
|
|
|
The code assumes that the graph is stored
|
|
|
|
as adjacency lists and maintains a queue
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
queue<int> q;
|
|
|
|
\end{lstlisting}
|
2017-01-07 17:30:14 +01:00
|
|
|
that contains the nodes 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.
|
|
|
|
|
|
|
|
In addition, the code uses arrays
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int z[N], e[N];
|
|
|
|
\end{lstlisting}
|
2017-01-07 17:30:14 +01:00
|
|
|
so that array \texttt{z} indicates
|
|
|
|
which nodes the search already has visited
|
|
|
|
and array \texttt{e} will contain the
|
|
|
|
minimum distance to all nodes in the graph.
|
|
|
|
The search can be implemented as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
z[s] = 1; e[x] = 0;
|
|
|
|
q.push(x);
|
|
|
|
while (!q.empty()) {
|
|
|
|
int s = q.front(); q.pop();
|
2017-01-07 17:30:14 +01:00
|
|
|
// process node s
|
2016-12-28 23:54:51 +01:00
|
|
|
for (auto u : v[s]) {
|
|
|
|
if (z[u]) continue;
|
|
|
|
z[u] = 1; e[u] = e[s]+1;
|
|
|
|
q.push(u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
\section{Sovelluksia}
|
|
|
|
|
|
|
|
Verkon läpikäynnin avulla
|
|
|
|
saa selville monia asioita
|
|
|
|
verkon rakenteesta.
|
|
|
|
Läpikäynnin voi yleensä aina toteuttaa
|
|
|
|
joko syvyyshaulla tai leveyshaulla,
|
|
|
|
mutta käytännössä syvyyshaku on parempi valinta,
|
|
|
|
koska sen toteutus on helpompi.
|
|
|
|
Oletamme seuraavaksi, että käsiteltävänä on
|
|
|
|
suuntaamaton verkko.
|
|
|
|
|
|
|
|
\subsubsection{Yhtenäisyyden tarkastaminen}
|
|
|
|
|
|
|
|
\index{yhtenxisyys@yhtenäisyys}
|
|
|
|
|
|
|
|
Verkko on yhtenäinen,
|
|
|
|
jos mistä tahansa solmuista
|
|
|
|
pääsee kaikkiin muihin solmuihin.
|
|
|
|
Niinpä verkon yhtenäisyys selviää
|
|
|
|
aloittamalla läpikäynti
|
|
|
|
jostakin verkon solmusta ja
|
|
|
|
tarkastamalla, pääseekö siitä kaikkiin solmuihin.
|
|
|
|
|
|
|
|
Esimerkiksi verkossa
|
|
|
|
\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);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
solmusta $1$ alkava syvyyshaku löytää seuraavat
|
|
|
|
solmut:
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle] (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$};
|
|
|
|
\node[draw, circle] (5) at (7,3) {$5$};
|
|
|
|
\node[draw, circle,fill=lightgray] (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=red,thick,->,line width=2pt] (1) -- (3);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (3) -- (4);
|
|
|
|
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
|
|
|
Koska syvyyshaku ei pääse kaikkiin solmuihin,
|
|
|
|
tämä tarkoittaa, että verkko ei ole yhtenäinen.
|
|
|
|
Vastaavalla tavalla voi etsiä myös verkon komponentit
|
|
|
|
käymällä solmut läpi ja aloittamalla uuden syvyyshaun
|
|
|
|
aina, jos käsiteltävä solmu ei kuulu vielä mihinkään komponenttiin.
|
|
|
|
|
|
|
|
\subsubsection{Syklin etsiminen}
|
|
|
|
|
|
|
|
\index{sykli@sykli}
|
|
|
|
|
|
|
|
Verkossa on sykli,
|
|
|
|
jos jonkin komponentin läpikäynnin
|
|
|
|
aikana tulee vastaan solmu,
|
|
|
|
jonka naapuri on jo käsitelty
|
|
|
|
ja solmuun ei ole saavuttu kyseisen naapurin kautta.
|
|
|
|
Esimerkiksi verkossa
|
|
|
|
\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$};
|
|
|
|
\node[draw, circle,fill=lightgray] (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);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (3);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (3) -- (2);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (2) -- (5);
|
|
|
|
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
on sykli, koska tultaessa solmusta 2 solmuun 5
|
|
|
|
havaitaan, että naapurina oleva solmu 3 on jo käsitelty.
|
|
|
|
Niinpä verkossa täytyy olla solmun 3 kautta
|
|
|
|
kulkeva sykli.
|
|
|
|
Tällainen sykli on esimerkiksi
|
|
|
|
$3 \rightarrow 2 \rightarrow 5 \rightarrow 3$.
|
|
|
|
|
|
|
|
Syklin olemassaolon voi myös päätellä laskemalla,
|
|
|
|
montako solmua ja kaarta komponentissa on.
|
|
|
|
Jos komponentissa on $c$ solmua ja siinä ei ole sykliä,
|
|
|
|
niin siinä on oltava tarkalleen $c-1$ kaarta.
|
|
|
|
Jos kaaria on $c$ tai enemmän, niin komponentissa
|
|
|
|
on varmasti sykli.
|
|
|
|
|
|
|
|
\subsubsection{Kaksijakoisuuden tarkastaminen}
|
|
|
|
|
|
|
|
\index{kaksijakoisuus@kaksijakoisuus}
|
|
|
|
|
|
|
|
Verkko on kaksijakoinen,
|
|
|
|
jos sen solmut voi värittää
|
|
|
|
kahdella värillä
|
|
|
|
niin, että kahta samanväristä
|
|
|
|
solmua ei ole vierekkäin.
|
|
|
|
On yllättävän helppoa selvittää
|
|
|
|
verkon läpikäynnin avulla,
|
|
|
|
onko verkko kaksijakoinen.
|
|
|
|
|
|
|
|
Ideana on värittää alkusolmu
|
|
|
|
siniseksi, sen kaikki naapurit
|
|
|
|
punaiseksi, niiden kaikki naapurit
|
|
|
|
siniseksi, jne.
|
|
|
|
Jos jossain vaiheessa
|
|
|
|
ilmenee ristiriita
|
|
|
|
(saman solmun tulisi olla sekä
|
|
|
|
sininen että punainen),
|
|
|
|
verkko ei ole kaksijakoinen.
|
|
|
|
Muuten verkko on kaksijakoinen
|
|
|
|
ja yksi väritys on muodostunut.
|
|
|
|
|
|
|
|
Esimerkiksi verkko
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle] (2) at (5,5) {$2$};
|
|
|
|
\node[draw, circle] (1) at (3,5) {$1$};
|
|
|
|
\node[draw, circle] (3) at (7,4) {$3$};
|
|
|
|
\node[draw, circle] (5) at (5,3) {$5$};
|
|
|
|
\node[draw, circle] (4) at (3,3) {$4$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (4);
|
|
|
|
\path[draw,thick,-] (4) -- (1);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (5) -- (3);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
ei ole kaksijakoinen, koska
|
|
|
|
läpikäynti solmusta 1 alkaen
|
|
|
|
aiheuttaa seuraavan ristiriidan:
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}
|
|
|
|
\node[draw, circle,fill=red!40] (2) at (5,5) {$2$};
|
|
|
|
\node[draw, circle,fill=blue!40] (1) at (3,5) {$1$};
|
|
|
|
\node[draw, circle,fill=blue!40] (3) at (7,4) {$3$};
|
|
|
|
\node[draw, circle,fill=red!40] (5) at (5,3) {$5$};
|
|
|
|
\node[draw, circle] (4) at (3,3) {$4$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (4);
|
|
|
|
\path[draw,thick,-] (4) -- (1);
|
|
|
|
\path[draw,thick,-] (2) -- (3);
|
|
|
|
\path[draw,thick,-] (5) -- (3);
|
|
|
|
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (2) -- (3);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (3) -- (5);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (5) -- (2);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
Tässä vaiheessa havaitaan,
|
|
|
|
että sekä solmun 2 että solmun 5 väri on punainen,
|
|
|
|
vaikka solmut ovat vierekkäin verkossa,
|
|
|
|
joten verkko ei ole kaksijakoinen.
|
|
|
|
|
|
|
|
Tämä algoritmi on luotettava tapa selvittää
|
|
|
|
verkon kaksijakoisuus,
|
|
|
|
koska kun värejä on vain kaksi,
|
|
|
|
ensimmäisen solmun värin valinta
|
|
|
|
määrittää kaikkien muiden
|
|
|
|
samassa komponentissa olevien
|
|
|
|
solmujen värin.
|
|
|
|
Ei ole merkitystä,
|
|
|
|
kumman värin ensimmäinen
|
|
|
|
solmu saa.
|
|
|
|
|
|
|
|
Huomaa, että yleensä ottaen on vaikeaa
|
|
|
|
selvittää, voiko verkon solmut
|
|
|
|
värittää $k$ värillä niin,
|
|
|
|
ettei missään kohtaa ole vierekkäin
|
|
|
|
kahta samanväristä solmua.
|
|
|
|
Edes tapaukseen $k=3$ ei tunneta
|
|
|
|
mitään tehokasta algoritmia,
|
|
|
|
vaan kyseessä on NP-vaikea ongelma.
|
|
|
|
%
|
|
|
|
% \section{Labyrintin käsittely}
|
|
|
|
%
|
|
|
|
% Labyrintti on ruudukko, joka muodostuu lattia- ja seinäruuduista,
|
|
|
|
% ja labyrintissa on sallittua kulkea lattiaruutuja pitkin.
|
|
|
|
% Labyrinttia
|
|
|
|
% \begin{center}
|
|
|
|
% \begin{tikzpicture}[scale=0.7]
|
|
|
|
% \fill[color=gray] (0,0) rectangle (8,1);
|
|
|
|
% \fill[color=gray] (0,5) rectangle (8,6);
|
|
|
|
% \fill[color=gray] (0,0) rectangle (1,6);
|
|
|
|
% \fill[color=gray] (7,0) rectangle (8,6);
|
|
|
|
%
|
|
|
|
% \fill[color=gray] (2,0) rectangle (3,4);
|
|
|
|
% \fill[color=gray] (4,2) rectangle (6,4);
|
|
|
|
%
|
|
|
|
% \draw (0,0) grid (8,6);
|
|
|
|
%
|
|
|
|
% \node at (1.5,1.5) {$a$};
|
|
|
|
% \node at (6.5,3.5) {$b$};
|
|
|
|
% \end{tikzpicture}
|
|
|
|
% \end{center}
|
|
|
|
% vastaa luontevasti verkko
|
|
|
|
% \begin{center}
|
|
|
|
% \begin{tikzpicture}[scale=0.7]
|
|
|
|
% \node[draw,circle,minimum size=20pt] (a) at (1,1) {$a$};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (b) at (1,2.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (c) at (1,4) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (d) at (1,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (e) at (2.5,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (f) at (4,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (g) at (5.5,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (h) at (7,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (i) at (8.5,5.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (j) at (8.5,4) {$b$};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (k) at (8.5,2.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (l) at (8.5,1) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (m) at (7,1) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (n) at (5.5,1) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (o) at (4,1) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (p) at (4,2.5) {};
|
|
|
|
% \node[draw,circle,minimum size=20pt] (q) at (4,4) {};
|
|
|
|
%
|
|
|
|
% \path[draw,thick,-] (a) -- (b);
|
|
|
|
% \path[draw,thick,-] (b) -- (c);
|
|
|
|
% \path[draw,thick,-] (c) -- (d);
|
|
|
|
% \path[draw,thick,-] (d) -- (e);
|
|
|
|
% \path[draw,thick,-] (e) -- (f);
|
|
|
|
% \path[draw,thick,-] (f) -- (g);
|
|
|
|
% \path[draw,thick,-] (g) -- (h);
|
|
|
|
% \path[draw,thick,-] (h) -- (i);
|
|
|
|
% \path[draw,thick,-] (i) -- (j);
|
|
|
|
% \path[draw,thick,-] (j) -- (k);
|
|
|
|
% \path[draw,thick,-] (k) -- (l);
|
|
|
|
% \path[draw,thick,-] (l) -- (m);
|
|
|
|
% \path[draw,thick,-] (m) -- (n);
|
|
|
|
% \path[draw,thick,-] (n) -- (o);
|
|
|
|
% \path[draw,thick,-] (o) -- (p);
|
|
|
|
% \path[draw,thick,-] (p) -- (q);
|
|
|
|
% \path[draw,thick,-] (q) -- (f);
|
|
|
|
% \end{tikzpicture}
|
|
|
|
% \end{center}
|
|
|
|
% jossa verkon solmuja ovat labyrintin lattiaruudut
|
|
|
|
% ja solmujen välillä on kaari, jos lattiaruudusta
|
|
|
|
% toiseen pääsee kulkemaan yhdellä askeleella.
|
|
|
|
% Niinpä erilaiset labyrinttiin liittyvät ongelmat
|
|
|
|
% palautuvat verkko-ongelmiksi.
|
|
|
|
%
|
|
|
|
% Esimerkiksi syvyyshaulla pystyy selvittämään,
|
|
|
|
% onko ruudusta $a$ reittiä ruutuun $b$
|
|
|
|
% ja leveyshaku kertoo lisäksi,
|
|
|
|
% mikä on pienin mahdollinen askelten määrä reitillä.
|
|
|
|
% Samoin voi esimerkiksi vaikkapa, kuinka monta
|
|
|
|
% toisistaan erillistä huonetta labyrintissa on
|
|
|
|
% sekä kuinka monta ruutua huoneissa on.
|
|
|
|
%
|
|
|
|
% Labyrintin tapauksessa ei kannata muodostaa erikseen
|
|
|
|
% verkkoa, vaan syvyyshaun ja leveyshaun voi toteuttaa
|
|
|
|
% suoraan labyrintin ruudukkoon.
|
|
|
|
|