Chapter 16 first version

This commit is contained in:
Antti H S Laaksonen 2017-01-08 17:36:46 +02:00
parent 2d13a03056
commit 88fc8746e2
1 changed files with 92 additions and 85 deletions

View File

@ -475,28 +475,29 @@ corresponds to a solution with minimum number of coins,
and the total number of paths from node 0 to node $x$ and the total number of paths from node 0 to node $x$
equals the total number of solutions. equals the total number of solutions.
\section{Tehokas eteneminen} \section{Successor paths}
\index{seuraajaverkko@seuraajaverkko} \index{successor graph}
\index{funktionaalinen verkko@funktionaalinen verkko} \index{functional graph}
Seuraavaksi oletamme, että For the rest of the chapter,
suunnaton verkko on \key{seuraajaverkko}, we concentrate on \key{successor graphs}
jolloin jokaisen solmun lähtöaste on 1 where the outdegree of each node is 1, i.e.,
eli siitä lähtee tasan yksi kaari ulospäin. exactly one edge begins at the node.
Niinpä verkko muodostuu yhdestä tai useammasta Thus, the graph consists of one or more
komponentista, joista jokaisessa on yksi sykli components, and each component contains
ja joukko siihen johtavia polkuja. one cycle and some paths that lead to it.
Seuraajaverkosta käytetään joskus nimeä Successor graphs are sometimes called
\key{funktionaalinen verkko}. \key{functional graphs}.
Tämä johtuu siitä, että jokaista seuraajaverkkoa The reason for this is that any successor graph
vastaa funktio $f$, joka määrittelee verkon kaaret. corresponds to a function $f$ that defines
Funktion parametrina on verkon solmu ja the edges in the graph.
se palauttaa solmusta lähtevän kaaren kohdesolmun. The parameter for the function is a node in the graph,
and the function returns the successor of the node.
\begin{samepage} \begin{samepage}
Esimerkiksi funktio For example, the function
\begin{center} \begin{center}
\begin{tabular}{r|rrrrrrrrr} \begin{tabular}{r|rrrrrrrrr}
$x$ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\ $x$ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
@ -505,7 +506,7 @@ $f(x)$ & 3 & 5 & 7 & 6 & 2 & 2 & 1 & 6 & 3 \\
\end{tabular} \end{tabular}
\end{center} \end{center}
\end{samepage} \end{samepage}
määrittelee seuraavan verkon: defines the following graph:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,0) {$1$}; \node[draw, circle] (1) at (0,0) {$1$};
@ -530,12 +531,13 @@ määrittelee seuraavan verkon:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Koska seuraajaverkon jokaisella solmulla Since each node in a successor graph has a
on yksikäsitteinen seuraaja, voimme määritellä funktion $f(x,k)$, unique successor, we can define a function $f(x,k)$
joka kertoo solmun, johon päätyy solmusta $x$ that returns the node that we will reach if
kulkemalla $k$ askelta. we begin at node $x$ and walk $k$ steps forward.
Esimerkiksi yllä olevassa verkossa $f(4,6)=2$, For example, in the above graph $f(4,6)=2$
koska solmusta 4 päätyy solmuun 2 kulkemalla 6 askelta: because by walking 6 steps from node 4,
we will reach node 2:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
@ -556,15 +558,16 @@ koska solmusta 4 päätyy solmuun 2 kulkemalla 6 askelta:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Suoraviivainen tapa laskea arvo $f(x,k)$ A straightforward way to calculate a value $f(x,k)$
on käydä läpi polku askel askeleelta, mihin kuluu aikaa $O(k)$. is to walk through the path step by step which takes $O(k)$ time.
Sopivan esikäsittelyn avulla voimme laskea kuitenkin However, using preprocessing, we can calculate any
minkä tahansa arvon $f(x,k)$ ajassa $O(\log k)$. value $f(x,k)$ in only $O(\log k)$ time.
Ideana on laskea etukäteen kaikki arvot $f(x,k)$, kun $k$ on 2:n potenssi The idea is to precalculate all values $f(x,k)$ where
ja enintään $u$, missä $u$ on suurin mahdollinen määrä $k$ is a power of two and at most $u$ where $u$ is
askeleita, joista olemme kiinnostuneita. the maximum number of steps we will ever walk.
Tämä onnistuu tehokkaasti, koska voimme käyttää rekursiota This can be done efficiently because
we can use the following recursion:
\begin{equation*} \begin{equation*}
f(x,k) = \begin{cases} f(x,k) = \begin{cases}
@ -573,9 +576,9 @@ Tämä onnistuu tehokkaasti, koska voimme käyttää rekursiota
\end{cases} \end{cases}
\end{equation*} \end{equation*}
Arvojen $f(x,k)$ esilaskenta vie aikaa $O(n \log u)$, Precalculating values $f(x,k)$ takes $O(n \log u)$ time
koska jokaisesta solmusta lasketaan $O(\log u)$ arvoa. because we calculate $O(\log u)$ values for each node.
Esimerkin tapauksessa taulukko alkaa muodostua seuraavasti: In the above graph, the first values are as follows:
\begin{center} \begin{center}
\begin{tabular}{r|rrrrrrrrr} \begin{tabular}{r|rrrrrrrrr}
@ -589,29 +592,29 @@ $\cdots$ \\
\end{tabular} \end{tabular}
\end{center} \end{center}
Tämän jälkeen funktion $f(x,k)$ arvon saa laskettua After this, any value $f(x,k)$ can be calculated
esittämällä luvun $k$ summana 2:n potensseja. by presenting the value $k$ as a sum of powers of two.
Esimerkiksi jos haluamme laskea arvon $f(x,11)$, For example, if we want to calculate the value $f(x,11)$,
muodostamme ensin esityksen $11=8+2+1$. we first form the representation $11=8+2+1$.
Tämän ansiosta Using this,
\[f(x,11)=f(f(f(x,8),2),1).\] \[f(x,11)=f(f(f(x,8),2),1).\]
Esimerkiksi yllä olevassa verkossa For example, in the above graph
\[f(4,11)=f(f(f(4,8),2),1)=5.\] \[f(4,11)=f(f(f(4,8),2),1)=5.\]
Tällaisessa esityksessä on aina Such a representation always consists of
$O(\log k)$ osaa, joten arvon $f(x,k)$ laskemiseen $O(\log k)$ parts so calculating a value $f(x,k)$
kuluu aikaa $O(\log k)$. takes $O(\log k)$ time.
\section{Syklin tunnistaminen} \section{Cycle detection}
\index{sykli@sykli} \index{cycle}
\index{syklin tunnistaminen@syklin tunnistaminen} \index{cycle detection}
Kiinnostavia kysymyksiä seuraajaverkossa ovat, Interesting questions in a successor graph are
minkä solmun kohdalla saavutaan sykliin which node is the first node in the cycle
solmusta $x$ lähdettäessä if we begin our walk at node $x$,
ja montako solmua kyseiseen sykliin kuuluu. and what is the size of the cycle.
Esimerkiksi verkossa For example, in the graph
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
@ -630,35 +633,37 @@ Esimerkiksi verkossa
\path[draw,thick,->] (6) -- (4); \path[draw,thick,->] (6) -- (4);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
solmusta 1 lähdettäessä ensimmäinen sykliin kuuluva if we begin at node 1, the first node that belongs
solmu on solmu 4 ja syklissä on kolme solmua to the cycle is node 4, and the cycle consists
(solmut 4, 5 ja 6). of three nodes (4, 5 and 6).
Helppo tapa tunnistaa sykli on alkaa kulkea verkossa An easy way to detect a cycle is to walk in the
solmusta $x$ alkaen ja pitää kirjaa kaikista vastaan tulevista graph beginning from node $x$ and keep track of
solmuista. Kun jokin solmu tulee vastaan toista kertaa, all visited nodes. Once we will visit a node
sykli on löytynyt. Tämän menetelmän aikavaativuus on $O(n)$ for the second time, the first node in the cycle has been found.
ja muistia kuluu myös $O(n)$. This method works in $O(n)$ time and also uses
$O(n)$ memory.
Osoittautuu kuitenkin, että syklin tunnistamiseen on However, there are better algorithms for cycle detection.
olemassa parempia algoritmeja. The time complexity of those algorithms is still $O(n)$,
Niissä aikavaativuus on edelleen $O(n)$, but they only use $O(1)$ memory.
mutta muistia kuluu vain $O(1)$. This is an important improvement if $n$ is large.
Tästä on merkittävää hyötyä, jos $n$ on suuri. Next we will learn Floyd's algorithm that
Tutustumme seuraavaksi Floydin algoritmiin, achieves these properties.
joka saavuttaa nämä ominaisuudet.
\subsubsection{Floydin algoritmi} \subsubsection{Floyd's algorithm}
\index{Floydin algoritmi@Floydin algoritmi} \index{Floyd's algorithm}
\key{Floydin algoritmi} kulkee verkossa eteenpäin rinnakkain \key{Floyd's algorithm} walks forward
kahdesta kohdasta. in the graph using two pointers $a$ and $b$.
Algoritmissa on kaksi osoitinta $a$ ja $b$, Both pointers begin at the starting node
jotka molemmat ovat ensin alkusolmussa. of the graph.
Osoitin $a$ liikkuu joka vuorolla askeleen eteenpäin, Then, on each turn, pointer $a$ walks
kun taas osoitin $b$ liikkuu kaksi askelta eteenpäin. one step forward, while pointer $b$
Haku jatkuu, kunnes osoittimet kohtaavat: walks two steps forward.
The search continues like that until
the pointers will meet each other:
\begin{lstlisting} \begin{lstlisting}
a = f(x); a = f(x);
@ -669,12 +674,13 @@ while (a != b) {
} }
\end{lstlisting} \end{lstlisting}
Tässä vaiheessa osoitin $a$ on kulkenut $k$ askelta At this point, pointer $a$ has walked $k$ steps,
ja osoitin $b$ on kulkenut $2k$ askelta, and pointer $b$ has walked $2k$ steps
missä $k$ on jaollinen syklin pituudella. where the length of the cycle divides $k$.
Niinpä ensimmäinen sykliin kuuluva solmu löytyy siirtämällä Thus, the first node that belongs to the cycle
osoitin $a$ alkuun ja liikuttamalla osoittimia can be found by moving pointer $a$ to the
rinnakkain eteenpäin, kunnes ne kohtaavat: starting node and advancing the pointers
step by step until they will meet again:
\begin{lstlisting} \begin{lstlisting}
a = x; a = x;
@ -684,9 +690,10 @@ while (a != b) {
} }
\end{lstlisting} \end{lstlisting}
Nyt $a$ ja $b$ osoittavat ensimmäiseen syklin Now $a$ and $b$ point to the first node in the cycle
solmuun, joka tulee vastaan solmusta $x$ lähdettäessä. that can be reached from node $x$.
Lopuksi syklin pituus $c$ voidaan laskea näin: Finally, the length $c$ of the cycle
can be calculated as follows:
\begin{lstlisting} \begin{lstlisting}
b = f(a); b = f(a);