cphb/luku12.tex

641 lines
19 KiB
TeX
Raw Normal View History

2016-12-28 23:54:51 +01:00
\chapter{Graph search}
Tässä luvussa tutustumme
syvyyshakuun ja leveyshakuun, jotka
ovat keskeisiä menetelmiä verkon läpikäyntiin.
Molemmat algoritmit lähtevät liikkeelle
tietystä alkusolmusta ja
käyvät läpi kaikki solmut,
joihin alkusolmusta pääsee.
Algoritmien erona on,
missä järjestyksessä ne kulkevat verkossa.
\section{Syvyyshaku}
\index{syvyyshaku@syvyyshaku}
\key{Syvyyshaku}
on suoraviivainen menetelmä verkon läpikäyntiin.
Algoritmi lähtee liikkeelle tietystä
verkon solmusta ja etenee siitä
kaikkiin solmuihin, jotka ovat
saavutettavissa kaaria kulkemalla.
Syvyyshaku etenee verkossa syvyyssuuntaisesti
eli kulkee eteenpäin verkossa niin kauan
kuin vastaan tulee uusia solmuja.
Tämän jälkeen haku perääntyy kokeilemaan
muita suuntia.
Algoritmi pitää kirjaa vierailemistaan solmuista,
jotta se käsittelee kunkin solmun vain kerran.
\subsubsection*{Esimerkki}
Tarkastellaan syvyyshaun toimintaa
seuraavassa verkossa:
\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}
Syvyyshaku voi lähteä liikkeelle
mistä tahansa solmusta,
mutta oletetaan nyt,
että haku lähtee liikkeelle solmusta 1.
Solmun 1 naapurit ovat solmut 2 ja 4,
joista haku etenee ensin solmuun 2:
\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}
Tämän jälkeen haku etenee vastaavasti
solmuihin 3 ja 5:
\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}
Solmun 5 naapurit ovat 2 ja 3,
mutta haku on käynyt jo molemmissa,
joten on aika peruuttaa taaksepäin.
Myös solmujen 3 ja 2 naapurit on käyty,
joten haku peruuttaa solmuun 1 asti.
Siitä lähtee kaari, josta pääsee
solmuun 4:
\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}
Tämän jälkeen haku päättyy,
koska se on käynyt kaikissa solmuissa.
Syvyyshaun aikavaativuus on $O(n+m)$,
missä $n$ on solmujen määrä ja $m$ on kaarten määrä,
koska haku käsittelee kerran jokaisen solmun ja kaaren.
\subsubsection*{Toteutus}
Syvyyshaku on yleensä mukavinta toteuttaa
rekursiolla.
Seuraava funktio \texttt{haku}
suorittaa syvyyshaun sille parametrina
annetusta solmusta lähtien.
Funktio olettaa, että
verkko on tallennettu vieruslistoina
taulukkoon
\begin{lstlisting}
vector<int> v[N];
\end{lstlisting}
ja pitää lisäksi yllä taulukkoa
\begin{lstlisting}
int z[N];
\end{lstlisting}
joka kertoo, missä solmuissa haku on käynyt.
Alussa taulukon jokainen arvo on 0,
ja kun haku saapuu solmuun $s$,
kohtaan \texttt{z}[$s$] merkitään 1.
Funktion toteutus on seuraavanlainen:
\begin{lstlisting}
void haku(int s) {
if (z[s]) return;
z[s] = 1;
// solmun s käsittely tähän
for (auto u: v[s]) {
haku(u);
}
}
\end{lstlisting}
\section{Leveyshaku}
\index{leveyshaku@leveyshaku}
\key{Leveyshaku}
käy solmut läpi järjestyksessä sen mukaan,
kuinka kaukana ne ovat alkusolmusta.
Niinpä leveyshaun avulla pystyy laskemaan
etäisyyden alkusolmusta kaikkiin
muihin solmuihin.
Leveyshaku on kuitenkin vaikeampi
toteuttaa kuin syvyyshaku.
Leveyshakua voi ajatella niin,
että se käy solmuja läpi kerros kerrallaan.
Ensin haku käy läpi solmut,
joihin pääsee yhdellä kaarella
alkusolmusta.
Tämän jälkeen vuorossa ovat
solmut, joihin pääsee kahdella
kaarella alkusolmusta, jne.
Sama jatkuu, kunnes uusia käsiteltäviä
solmuja ei enää ole.
\subsubsection*{Esimerkki}
Tarkastellaan leveyshaun toimintaa
seuraavassa verkossa:
\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}
Oletetaan jälleen,
että haku alkaa solmusta 1.
Haku etenee ensin kaikkiin solmuihin,
joihin pääsee alkusolmusta:
\\
\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}
Seuraavaksi haku etenee solmuihin 3 ja 5:
\\
\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}
Viimeisenä haku etenee solmuun 6:
\\
\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}
Leveyshaun tuloksena selviää etäisyys
kuhunkin verkon solmuun alkusolmusta.
Etäisyys on sama kuin kerros,
jossa solmu käsiteltiin haun aikana:
\begin{tabular}{ll}
\\
solmu & etäisyys \\
\hline
1 & 0 \\
2 & 1 \\
3 & 2 \\
4 & 1 \\
5 & 2 \\
6 & 3 \\
\\
\end{tabular}
Leveyshaun aikavaativuus on syvyyshaun tavoin $O(n+m)$,
missä $n$ on solmujen määrä ja $m$ on kaarten määrä.
\subsubsection*{Toteutus}
Leveyshaku on syvyyshakua hankalampi toteuttaa,
koska haku käy läpi solmuja verkon eri
puolilta niiden etäisyyden mukaan.
Tyypillinen toteutus on pitää yllä jonoa
käsiteltävistä solmuista.
Joka askeleella otetaan käsittelyyn seuraava
solmu jonosta ja uudet solmut lisätään
jonon perälle.
Seuraava koodi toteuttaa leveyshaun
solmusta $x$ lähtien.
Koodi olettaa, että verkko on tallennettu
vieruslistoina, ja pitää yllä jonoa
\begin{lstlisting}
queue<int> q;
\end{lstlisting}
joka sisältää solmut käsittelyjärjestyksessä.
Koodi lisää aina uudet vastaan tulevat solmut
jonon perään ja ottaa seuraavaksi käsiteltävän
solmun jonon alusta,
minkä ansiosta solmut käsitellään
kerroksittain alkusolmusta lähtien.
Lisäksi koodi käyttää taulukoita
\begin{lstlisting}
int z[N], e[N];
\end{lstlisting}
niin, että taulukko \texttt{z} sisältää tiedon,
missä solmuissa haku on käynyt,
ja taulukkoon \texttt{e} lasketaan lyhin
etäisyys alkusolmusta kaikkiin verkon solmuihin.
Toteutuksesta tulee seuraavanlainen:
\begin{lstlisting}
z[s] = 1; e[x] = 0;
q.push(x);
while (!q.empty()) {
int s = q.front(); q.pop();
// solmun s käsittely tähän
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.