Chapter 30 first version

This commit is contained in:
Antti H S Laaksonen 2017-01-29 18:40:11 +02:00
parent 0a9b4770ef
commit 45279464a3
1 changed files with 146 additions and 161 deletions

View File

@ -1,33 +1,31 @@
\chapter{Sweep line} \chapter{Sweep line algorithms}
\index{pyyhkxisyviiva@pyyhkäisyviiva} \index{sweep line}
\key{Pyyhkäisyviiva} on tason halki kulkeva viiva, Many geometric problems can be solved using
jonka avulla voi ratkaista useita geometrisia tehtäviä. \key{sweep line} algorithms.
Ideana on esittää tehtävä joukkona tapahtumia, The idea in such algorithms is to represent
jotka vastaavat tason pisteitä. the problem as a set of events that correspond
Kun pyyhkäisyviiva törmää pisteeseen, to points in the plane.
tapahtuma käsitellään ja tehtävän ratkaisu edistyy. The events are processed in a sorted order
according to their x or y coordinate.
Tarkastellaan esimerkkinä tekniikan As an example, let us consider a problem
käyttämisestä tehtävää, where there is a company that has $n$ employees,
jossa yrityksessä on töissä $n$ henkilöä and we know for each employee arrival and
ja jokaisesta henkilöstä tiedetään, leaving times on a certain day.
milloin hän tuli töihin ja lähti töistä Our task is to calculate the maximum number of
tiettynä päivänä. employees that were in the office at the same time.
Tehtävänä on laskea,
mikä on suurin määrä henkilöitä,
jotka olivat samaan aikaan töissä.
Tehtävän voi ratkaista mallintamalla tilanteen The problem can be solved by modelling the situation
niin, että jokaista henkilöä vastaa kaksi tapahtumaa: so that each employee is assigned two events that
tuloaika töihin ja lähtöaika töistä. corresponds to the arrival and leaving times.
Pyyhkäisyviiva käy läpi tapahtumat aikajärjestyksessä After sorting the events, we can go trough them
ja pitää kirjaa, montako henkilöä oli töissä milloinkin. and keep track of the number of people in the office.
Esimerkiksi tilannetta For example, the table
\begin{center} \begin{center}
\begin{tabular}{ccc} \begin{tabular}{ccc}
henkilö & tuloaika & lähtöaika \\ person & arrival time & leaving time \\
\hline \hline
Uolevi & 10 & 15 \\ Uolevi & 10 & 15 \\
Maija & 6 & 12 \\ Maija & 6 & 12 \\
@ -35,7 +33,7 @@ Kaaleppi & 14 & 16 \\
Liisa & 5 & 13 \\ Liisa & 5 & 13 \\
\end{tabular} \end{tabular}
\end{center} \end{center}
vastaavat seuraavat tapahtumat: generates the following events:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.6] \begin{tikzpicture}[scale=0.6]
\draw (0,0) rectangle (17,-6.5); \draw (0,0) rectangle (17,-6.5);
@ -59,15 +57,16 @@ vastaavat seuraavat tapahtumat:
\node at (2,-5.5) {Liisa}; \node at (2,-5.5) {Liisa};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Pyyhkäisyviiva käy läpi tapahtumat vasemmalta oikealle We go through the events from left to right
ja pitää yllä laskuria. and maintain a counter.
Aina kun henkilö tulee töihin, laskurin arvo Always when a person arrives, we increase
kasvaa yhdellä, ja kun henkilö lähtee töistä, the value of the counter by one,
laskurin arvo vähenee yhdellä. and when a person leaves,
Tehtävän ratkaisu on suurin laskuri arvo we decrease the value by one.
pyyhkäisyviivan kulun aikana. The answer for the problem is the maximum
value of the counter during the algorithm.
Pyyhkäisyviiva kulkee seuraavasti tason halki: In the example, the events are processed as follows:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.6] \begin{tikzpicture}[scale=0.6]
\path[draw,thick,->] (0.5,0.5) -- (16.5,0.5); \path[draw,thick,->] (0.5,0.5) -- (16.5,0.5);
@ -119,26 +118,24 @@ Pyyhkäisyviiva kulkee seuraavasti tason halki:
\node at (13,-8) {$1$}; \node at (13,-8) {$1$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Kuvan alareunan merkinnät $+$ ja $-$ The symbols $+$ and $-$ indicate whether the
tarkoittavat, että laskurin arvo kasvaa value of the counter increases of decreases,
ja vähenee yhdellä. and the value of the counter is shown below.
Niiden alapuolella on laskurin uusi arvo. The maximum value of the counter is 3
Laskurin suurin arvo 3 on voimassa between Uolevi's arrival and Maija's leaving.
Uolevi tulohetken ja Maijan lähtöhetken välillä.
Ratkaisun aikavaativuus on $O(n \log n)$, The running time of the solution is $O(n \log n)$,
koska tapahtumien järjestäminen vie aikaa $O(n \log n)$ because sorting the events takes $O(n \log n)$ time
ja pyyhkäisyviivan läpikäynti vie aikaa $O(n)$. and the rest of the algorithm takes $O(n)$ time.
\section{Janojen leikkauspisteet} \section{Intersection points}
\index{leikkauspiste@leikkauspiste} \index{intersection point}
Annettuna on $n$ janaa, joista jokainen Given a set of $n$ line segments, each of them being either
on vaaka- tai pystysuuntainen. horizontal or vertical, the problem is to efficiently
Tehtävänä on laskea tehokkaasti, monessako pisteessä calculate the total number of intersection points.
kaksi janaa leikkaavat toisensa. For example, when the line segments are
Esimerkiksi tilanteessa
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.5] \begin{tikzpicture}[scale=0.5]
\path[draw,thick,-] (0,2) -- (5,2); \path[draw,thick,-] (0,2) -- (5,2);
@ -148,7 +145,7 @@ Esimerkiksi tilanteessa
\path[draw,thick,-] (8,2) -- (8,5); \path[draw,thick,-] (8,2) -- (8,5);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
leikkauspisteitä on kolme: there are three intersection points:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.5] \begin{tikzpicture}[scale=0.5]
\path[draw,thick,-] (0,2) -- (5,2); \path[draw,thick,-] (0,2) -- (5,2);
@ -164,21 +161,20 @@ leikkauspisteitä on kolme:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
It is easy to solve the problem in $O(n^2)$ time,
because we can go through all possible pairs of segments
and check if they intersect.
However, we can solve the problem more efficiently
in $O(n \log n)$ time using a sweep line algorithm.
Tehtävä on helppoa ratkaista ajassa $O(n^2)$, The idea is to generate two types of events:
koska riittää käydä läpi kaikki mahdolliset janaparit
ja tarkistaa, moniko leikkaa toisiaan.
Seuraavaksi ratkaisemme tehtävän
ajassa $O(n \log n)$ pyyhkäisyviivan avulla.
Ideana on luoda janoista kolmenlaisia tapahtumia:
\begin{enumerate}[noitemsep] \begin{enumerate}[noitemsep]
\item[(1)] vaakajana alkaa \item[(1)] horizontal segment begins
\item[(2)] vaakajana päättyy \item[(2)] horizontal segment ends
\item[(3)] pystyjana \item[(3)] vertical segment
\end{enumerate} \end{enumerate}
Esimerkkitilannetta vastaava pistejoukko on seuraava: The following events correspond to the example:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.6] \begin{tikzpicture}[scale=0.6]
\path[draw,dashed] (0,2) -- (5,2); \path[draw,dashed] (0,2) -- (5,2);
@ -199,37 +195,35 @@ Esimerkkitilannetta vastaava pistejoukko on seuraava:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Algoritmi käy läpi pisteet vasemmalta oikealle We go through the events from left to right
ja pitää yllä tietorakennetta y-koordinaateista, and use a data structure that maintains a set of
joissa on tällä hetkellä aktiivinen vaakajana. y coordinates where there is an active horizontal segment.
Tapahtuman 1 kohdalla vaakajanan y-koordinaatti At event 1, we add the y coordinate of the segment
lisätään joukkoon ja tapahtuman 2 kohdalla to the set, and at event 2, we remove the
vaakajanan y-koordinaatti poistetaan joukosta. y coordinate from the set.
Algoritmi laskee janojen leikkauspisteet Intersection points are calculated at event 3.
tapahtumien 3 kohdalla. When there is a vertical segment between points
Kun pystyjana kulkee y-koordinaattien $y_1$ and $y_2$, we count the number of active
$y_1 \ldots y_2$ välillä, horizontal segments whose y coordinate is between
algoritmi laskee tietorakenteesta, $y_1$ and $y_2$, and at this number to the total
monessako vaakajanassa on y-koordinaatti number of intersection points.
välillä $y_1 \ldots y_2$ ja kasvattaa
leikkauspisteiden määrää tällä arvolla.
Sopiva tietorakenne vaakajanojen y-koordinaattien An appropriate data structure for storing
tallentamiseen on bi\-nää\-ri-indeksipuu tai segmenttipuu, y coordinates of horizontal segments is either
johon on tarvittaessa yhdistetty indeksien pakkaus. a binary-indexed tree or a segment tree,
Tällöin jokaisen pisteen käsittely possibly with index compression.
vie aikaa $O(\log n)$, joten algoritmin Using such structures, processing each event
kokonaisaikavaativuus on $O(n \log n)$. takes $O(\log n)$ time, so the total running
time of the algorithm is $O(n \log n)$.
\section{Lähin pistepari} \section{Nearest points}
\index{lzhin pistepari@lähin pistepari} \index{nearest points}
Seuraava tehtävämme on etsiä $n$ pisteen Given a set of $n$ points, our next problem is
joukosta kaksi pistettä, jotka ovat to find two points whose distance is minimum.
mahdollisimman lähellä toisiaan. For example, if the points are
Esimerkiksi tilanteessa
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0)--(12,0)--(12,4)--(0,4)--(0,0); \draw (0,0)--(12,0)--(12,4)--(0,4)--(0,0);
@ -251,7 +245,7 @@ Esimerkiksi tilanteessa
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\begin{samepage} \begin{samepage}
lähin pistepari on seuraava: we should find the following points:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0)--(12,0)--(12,4)--(0,4)--(0,0); \draw (0,0)--(12,0)--(12,4)--(0,4)--(0,0);
@ -274,32 +268,30 @@ lähin pistepari on seuraava:
\end{center} \end{center}
\end{samepage} \end{samepage}
Tämäkin tehtävä ratkeaa This problem can be also solved in $O(n \log n)$ time
$O(n \log n)$-ajassa pyyhkäisyviivan avulla. using a sweep line algorithm.
Algoritmi käy pisteet läpi vasemmalta oikealle We go through the points from left to right
ja pitää yllä arvoa $d$, and maintain a value $d$: the minimum distance
joka on pienin kahden between two points so far.
pisteen etäisyys. At each point, we find the nearest point to the left.
Kunkin pisteen kohdalla algoritmi If the distance is less than $d$, it is the
etsii lähimmän toisen pisteen vasemmalta. new minimum distance and we update
Jos etäisyys tähän pisteeseen on alle $d$, the value of $d$.
tämä on uusi pienin kahden pisteen etäisyys
ja algoritmi päivittää $d$:n arvon.
Jos käsiteltävä piste on $(x,y)$ If the current point is $(x,y)$
ja jokin vasemmalla oleva piste on and there is a point to the left
alle $d$:n etäisyydellä, within a distance of less than $d$,
sen x-koordinaatin the x coordinate of such a point must
tulee olla välillä $[x-d,x]$ be between $[x-d,x]$ and the y coordinate
ja y-koordinaatin tulee olla välillä $[y-d,y+d]$. must be between $[y-d,y+d]$.
Algoritmin riittää siis tarkistaa Thus, it suffices to only consider points
ainoastaan pisteet, jotka osuvat tälle välille, that are located in those ranges,
mikä tehostaa hakua merkittävästi. which makes the algorithm efficient.
Esimerkiksi seuraavassa kuvassa For example, in the following picture the
katkoviiva-alue sisältää pisteet, region marked with dashed lines contains
jotka voivat olla alle $d$:n etäisyydellä the points that can be within a distance of $d$
tummennetusta pisteestä. from the active point:
\\ \\
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
@ -332,34 +324,31 @@ tummennetusta pisteestä.
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Algoritmin tehokkuus perustuu siihen, The efficiency of the algorithm is based on the fact
että $d$:n rajoittamalla alueella that the region limited by $d$ always contains
on aina vain $O(1)$ pistettä. only $O(1)$ points.
Nämä pisteet pystyy käymään läpi We can go through those points in $O(\log n)$ time
$O(\log n)$-aikaisesti by maintaining a set of points whose x coordinate
pitämällä algoritmin aikana yllä joukkoa pisteistä, is between $[x-d,x]$ and that are sorted according
joiden x-koordinaatti on välillä $[x-d,x]$ to the y coordinate.
ja jotka on järjestetty y-koordinaatin mukaan.
Algoritmin aikavaativuus on $O(n \log n)$, The time complexity of the algorithm is $O(n \log n)$,
koska se käy läpi $n$ pistettä because it goes through $n$ points and
ja etsii jokaiselle lähimmän finds for each point the nearest point to the left
edeltävän pisteen ajassa $O(\log n)$. in $O(\log n)$ time.
\section{Konveksi peite} \section{Convex hull}
\key{Konveksi peite} The \key{convex hull} is the smallest convex polygon
on pienin konveksi monikulmio, that contains all points in a given set.
joka ympäröi kaikki pistejoukon pisteet. Convexity means that a line segment between
Konveksius tarkoittaa, any two vertices of the polygon is completely
että minkä tahansa kahden kärkipisteen välinen jana inside the polygon.
kulkee monikulmion sisällä. A good intuitive definition is that we surround
Hyvä mielikuva asiasta on, the points using a tight rope.
että pistejoukko ympäröidään tiukasti
viritetyllä narulla.
\begin{samepage} \begin{samepage}
Esimerkiksi pistejoukon For example, for the points
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0) circle [radius=0.1]; \draw (0,0) circle [radius=0.1];
@ -379,7 +368,7 @@ Esimerkiksi pistejoukon
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\end{samepage} \end{samepage}
konveksi peite on seuraava: the convex hull is as follows:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0)--(4,-1)--(7,1)--(6,3)--(2,4)--(0,2)--(0,0); \draw (0,0)--(4,-1)--(7,1)--(6,3)--(2,4)--(0,2)--(0,0);
@ -401,34 +390,30 @@ konveksi peite on seuraava:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\index{Andrew'n algoritmi} \index{Andrew's algorithm}
Tehokas ja helposti toteutettava menetelmä A good way to construct the convex hull
konveksin peitteen muodostamiseen is \key{Andrew's algorithm}
on \key{Andrew'n algoritmi}, that works in $O(n \log n)$ time.
jonka aikavaativuus on $O(n \log n)$. The algorithm constructs the convex hull
Algoritmi muodostaa konveksin peitteen kahdessa in two steps:
osassa: ensin peitteen yläosan ja sitten peitteen alaosan. first the upper hull and then the lower hull.
Kummankin osan muodostaminen tapahtuu samalla tavalla, Both steps are similar, so we can focus on
minkä vuoksi voimme keskittyä yläosan muodostamiseen. constructing the upper hull.
Algoritmi järjestää ensin pisteet ensisijaisesti x-koordinaatin We sort the points primarily according to
ja toissijaisesti y-koordinaatin mukaan. x coordinates and secondarily according to y coordinates.
Tämän jälkeen se käy pisteet läpi järjestyksessä After this, we go through the points and always
ja lisää aina uuden pisteen osaksi peitettä. add the new point to the hull.
Aina pisteen lisäämisen jälkeen algoritmi tarkastaa After adding a point we check using cross products
ristitulon avulla, whether the tree last point in the hull turn left.
muodostavatko kolme viimeistä pistettä peitteessä If this holds, we remove the middle point from the hull.
vasemmalle kääntyvän osan. After this we keep checking again the three last points
Jos näin on, and removing points, until the three last points
algoritmi poistaa näistä keskimmäisen pisteen. don't turn left.
Tämän jälkeen algoritmi tarkastaa uudestaan
kolme viimeistä pistettä ja poistaa taas tarvittaessa
keskimmäisen pisteen.
Sama jatkuu, kunnes kolme viimeistä pistettä
eivät muodosta vasemmalle kääntyvää osaa.
Seuraava kuvasarja esittää Andrew'n algoritmin toimintaa: The following pictures show how
Andrew's algorithm works:
\\ \\
\begin{tabular}{ccccccc} \begin{tabular}{ccccccc}
\\ \\