Chapter 6 ready

This commit is contained in:
Antti H S Laaksonen 2017-01-02 00:34:14 +02:00
parent c0b6c97340
commit 66f167a6eb
1 changed files with 176 additions and 169 deletions

View File

@ -264,22 +264,20 @@ possibilities to select for the next events,
compared to the strategy that we select the
event that ends as soon as possible.
\section{Tehtävät ja deadlinet}
\section{Tasks and deadlines}
Annettuna on $n$ tehtävää,
joista jokaisella on kesto ja deadline.
Tehtäväsi on valita järjestys,
jossa suoritat tehtävät.
Saat kustakin tehtävästä $d-x$ pistettä,
missä $d$ on tehtävän deadline ja $x$
on tehtävän valmistumishetki.
Mikä on suurin mahdollinen
yhteispistemäärä, jonka voit saada tehtävistä?
We are given $n$ tasks with duration and deadline.
Our task is to choose an order to perform the tasks.
For each task, we get $d-x$ points
where $d$ is the deadline of the task
and $x$ is the moment when we finished the task.
What is the largest possible total score
we can obtain?
Esimerkiksi jos tehtävät ovat
For example, if the tasks are
\begin{center}
\begin{tabular}{lll}
tehtävä & kesto & deadline \\
task & duration & deadline \\
\hline
$A$ & 4 & 2 \\
$B$ & 3 & 5 \\
@ -287,8 +285,8 @@ $C$ & 2 & 7 \\
$D$ & 4 & 5 \\
\end{tabular}
\end{center}
niin optimaalinen ratkaisu on suorittaa
tehtävät seuraavasti:
then the optimal solution is to perform
the tasks as follows:
\begin{center}
\begin{tikzpicture}[scale=.4]
\begin{scope}
@ -314,22 +312,21 @@ tehtävät seuraavasti:
\end{scope}
\end{tikzpicture}
\end{center}
Tässä ratkaisussa $C$ tuottaa 5 pistettä,
$B$ tuottaa 0 pistettä, $A$ tuottaa $-7$ pistettä
ja $D$ tuottaa $-8$ pistettä,
joten yhteispistemäärä on $-10$.
In this solution, $C$ yields 5 points,
$B$ yields 0 points, $A$ yields $-7$ points
and $D$ yields $-8$ points,
so the total score is $-10$.
Yllättävää kyllä, tehtävän optimaalinen ratkaisu
ei riipu lainkaan deadlineista,
vaan toimiva ahne strategia on
yksinkertaisesti
suorittaa tehtävät \emph{järjestyksessä keston mukaan}
lyhimmästä pisimpään.
Syynä tähän on, että jos missä tahansa vaiheessa
suoritetaan peräkkäin kaksi tehtävää,
joista ensimmäinen kestää toista kauemmin,
tehtävien järjestyksen vaihtaminen parantaa ratkaisua.
Esimerkiksi jos peräkkäin ovat tehtävät
Surprisingly, the optimal solution for the problem
doesn't depend on the dedalines at all,
but a correct greedy strategy is to simply
perform the tasks \emph{sorted by their durations}
in increasing order.
The reason for this is that if we ever perform
two successive tasks such that the first task
takes longer than the second task,
we can obtain a better solution if we swap the tasks.
For example, if the successive tasks are
\begin{center}
\begin{tikzpicture}[scale=.4]
\begin{scope}
@ -348,7 +345,7 @@ Esimerkiksi jos peräkkäin ovat tehtävät
\end{scope}
\end{tikzpicture}
\end{center}
ja $a>b$, niin järjestyksen muuttaminen muotoon
and $a>b$, the swapped order of the tasks
\begin{center}
\begin{tikzpicture}[scale=.4]
\begin{scope}
@ -367,97 +364,102 @@ ja $a>b$, niin järjestyksen muuttaminen muotoon
\end{scope}
\end{tikzpicture}
\end{center}
antaa $X$:lle $b$ pistettä vähemmän ja $Y$:lle $a$ pistettä enemmän,
joten kokonaismuutos pistemäärään on $a-b > 0$.
Optimiratkaisussa
kaikille peräkkäin suoritettaville tehtäville
tulee päteä, että lyhyempi tulee ennen pidempää,
mistä seuraa, että tehtävät tulee suorittaa
järjestyksessä keston mukaan.
gives $b$ points less to $X$ and $a$ points more to $Y$,
so the total score increases by $a-b > 0$.
In an optimal solution,
for each two successive tasks,
it must hold that the shorter task comes
before the longer task.
Thus, the tasks must be performed
sorted by their durations.
\section{Keskiluvut}
\section{Minimizing sums}
Tarkastelemme seuraavaksi ongelmaa, jossa
annettuna on $n$ lukua $a_1,a_2,\ldots,a_n$
ja tehtävänä on etsiä luku $x$ niin, että summa
We will next consider a problem where
we are given $n$ numbers $a_1,a_2,\ldots,a_n$
and our task is to find a value $x$
such that the sum
\[|a_1-x|^c+|a_2-x|^c+\cdots+|a_n-x|^c\]
on mahdollisimman pieni.
Keskitymme tapauksiin, joissa $c=1$ tai $c=2$.
becomes as small as possible.
We will focus on the cases $c=1$ and $c=2$.
\subsubsection{Tapaus $c=1$}
\subsubsection{Case $c=1$}
Tässä tapauksessa minimoitavana on summa
In this case, we should minimize the sum
\[|a_1-x|+|a_2-x|+\cdots+|a_n-x|.\]
Esimerkiksi jos luvut ovat $[1,2,9,2,6]$,
niin paras ratkaisu on valita $x=2$,
jolloin summaksi tulee
For example, if the numbers are $[1,2,9,2,6]$,
the best solution is to select $x=2$
which produces the sum
\[
|1-2|+|2-2|+|9-2|+|2-2|+|6-2|=12.
\]
Yleisessä tapauksessa paras valinta $x$:n arvoksi
on lukujen \textit{mediaani}
eli keskimmäinen luku järjestyksessä.
Esimerkiksi luvut $[1,2,9,2,6]$
ovat järjestyksessä $[1,2,2,6,9]$,
joten mediaani on 2.
In the general case, the best choice for $x$
is the \textit{median} of the numbers,
i.e., the middle number after sorting.
For example, the list $[1,2,9,2,6]$
becomes $[1,2,2,6,9]$ after sorting,
so the median is 2.
Mediaanin valinta on paras ratkaisu,
koska jos $x$ on mediaania pienempi,
$x$:n suurentaminen pienentää summaa,
ja vastaavasti jos $x$ on mediaania suurempi,
$x$:n pienentäminen pienentää summaa.
Niinpä $x$ kannattaa siirtää mahdollisimman
lähelle mediaania eli optimiratkaisu on
valita $x$ mediaaniksi.
Jos $n$ on parillinen ja mediaaneja on kaksi,
kumpikin mediaani sekä kaikki niiden välillä
olevat luvut tuottavat optimaalisen ratkaisun.
The median is the optimal choice,
because if $x$ is smaller than the median,
the sum becomes smaller by increasing $x$,
and if $x$ is larger then the median,
the sum becomes smaller by decreasing $x$
Thus, we should move $x$ as near the median
as possible, so the optimal solution that $x$
is the median.
If $n$ is even and there are two medians,
both medians and all values between them
are optimal solutions.
\subsubsection{Tapaus $c=2$}
\subsubsection{Case $c=2$}
Tässä tapauksessa minimoitavana on summa
In this case, we should minimize the sum
\[(a_1-x)^2+(a_2-x)^2+\cdots+(a_n-x)^2.\]
Esimerkiksi jos luvut ovat $[1,2,9,2,6]$,
niin paras ratkaisu on $x=4$,
jolloin summaksi tulee
For example, if the numbers are $[1,2,9,2,6]$,
the best solution is to select $x=4$
which produces the sum
\[
(1-4)^2+(2-4)^2+(9-4)^2+(2-4)^2+(6-4)^2=46.
\]
Yleisessä tapauksessa paras valinta $x$:n arvoksi on lukujen
\textit{keskiarvo}.
Esimerkissä lukujen keskiarvo on $(1+2+9+2+6)/5=4$.
Tämän tuloksen voi johtaa järjestämällä summan
uudestaan muotoon
In the general case, the best choice for $x$
is the \emph{average} of the numbers.
In the example the average is $(1+2+9+2+6)/5=4$.
This result can be derived by presenting
the sum as follows:
\[
nx^2 - 2x(a_1+a_2+\cdots+a_n) + (a_1^2+a_2^2+\cdots+a_n^2).
\]
Viimeinen osa ei riipu $x$:stä, joten sen voi jättää huomiotta.
Jäljelle jäävistä osista muodostuu funktio
$nx^2-2xs$, kun $s=a_1+a_2+\cdots+a_n$.
Tämä on ylöspäin aukeava paraabeli,
jonka nollakohdat ovat $x=0$ ja $x=2s/n$
ja pienin arvo on näiden keskikohta
$x=s/n$ eli taulukon lukujen keskiarvo.
The last part doesn't depend on $x$,
so we can ignore it.
The remaining parts form a function
$nx^2-2xs$ where $s=a_1+a_2+\cdots+a_n$.
This is a parabola opening upwards
with roots $x=0$ and $x=2s/n$,
and the minimum value is the average
of the roots $x=s/n$, i.e.,
the average of the numbers $a_1,a_2,\ldots,a_n$.
\section{Tiedonpakkaus}
\section{Data compression}
\index{tiedonpakkaus}
\index{binxxrikoodi@binäärikoodi}
\index{koodisana@koodisana}
\index{data compression}
\index{binary code}
\index{codeword}
Annettuna on merkkijono ja tehtävänä on
\emph{pakata} se niin,
että tilaa kuluu vähemmän.
Käytämme tähän \key{binäärikoodia},
joka määrittää kullekin merkille
biteistä muodostuvan \key{koodisanan}.
Tällöin merkkijonon voi pakata
korvaamalla jokaisen merkin vastaavalla koodisanalla.
Esimerkiksi seuraava binäärikoodi määrittää
koodisanat merkeille \texttt{A}\texttt{D}:
We are given a string, and our task is to
\emph{compress} it so that it requires less space.
We will do this using a \key{binary code}
that determines for each character
a \key{codeword} that consists of bits.
After this, we can compress the string
by replacing each character by the
corresponding codeword.
For example, the following binary code
determines codewords for characters
\texttt{A}\texttt{D}:
\begin{center}
\begin{tabular}{rr}
merkki & koodisana \\
character & codeword \\
\hline
\texttt{A} & 00 \\
\texttt{B} & 01 \\
@ -465,23 +467,25 @@ merkki & koodisana \\
\texttt{D} & 11 \\
\end{tabular}
\end{center}
Tämä koodi on \key{vakiopituinen}
eli jokainen koodisana on yhtä pitkä.
Esimerkiksi merkkijono
\texttt{AABACDACA} on pakattuna
This is a \key{constant-length} code
which means that the length of each
codeword is the same.
For example, the compressed form of the string
\texttt{AABACDACA} is
\[000001001011001000,\]
eli se vie tilaa 18 bittiä.
Pakkausta on kuitenkin mahdollista parantaa
ottamalla käyttöön \key{muuttuvan pituinen} koodi,
jossa koodisanojen pituus voi vaihdella.
Tällöin voimme antaa usein esiintyville merkeille
lyhyen koodisanan ja harvoin esiintyville
merkeille pitkän koodisanan.
Osoittautuu, että yllä olevalle merkkijonolle
\key{optimaalinen} koodi on seuraava:
so 18 bits are needed.
However, we can compress the string better
by using a \key{variable-length} code
where codewords may have different lengths.
Then we can give short codewords for
characters that appear often,
and long codewords for characters
that appear rarely.
It turns out that the \key{optimal} code
for the aforementioned string is as follows:
\begin{center}
\begin{tabular}{rr}
merkki & koodisana \\
character & codeword \\
\hline
\texttt{A} & 0 \\
\texttt{B} & 110 \\
@ -489,27 +493,26 @@ merkki & koodisana \\
\texttt{D} & 111 \\
\end{tabular}
\end{center}
Optimaalinen koodi tuottaa
mahdollisimman lyhyen pakatun merkkijonon.
Tässä tapauksessa optimaalinen koodi
pakkaa merkkijonon muotoon
The optimal code produces a compressed string
that is as short as possible.
In this case, the compressed form using
the optimal code is
\[001100101110100,\]
ja tilaa kuluu vain 15 bittiä.
Paremman koodin ansiosta onnistuimme siis säästämään
3 bittiä tilaa pakkauksessa.
so only 15 bits are needed.
Thus, thanks to a better code it was possible to
save 3 bits in the compressed string.
Huomaa, että koodin tulee olla aina sellainen,
että mikään koodisana ei ole toisen koodisanan
alkuosa.
Esimerkiksi ei ole sallittua, että koodissa
olisi molemmat koodisanat 10 ja 1011.
Tämä rajoitus johtuu siitä,
että haluamme myös pystyä palauttamaan
alkuperäisen merkkijonon pakkauksen jälkeen.
Jos koodisana voisi olla toisen alkuosa,
tämä ei välttämättä olisi mahdollista.
Esimerkiksi seuraava koodi
\emph{ei} ole kelvollinen:
Note that it is required that no codeword
is a prefix of another codeword.
For example, it is not allowed that a code
would contain both codewords 10
and 1011.
The reason for this is that we also want
to be able to generate the original string
from the compressed string.
If a codeword could be a prefix of another codeword,
this would not always be possible.
For example, the following code is \emph{not} valid:
\begin{center}
\begin{tabular}{rr}
merkki & koodisana \\
@ -520,40 +523,41 @@ merkki & koodisana \\
\texttt{D} & 111 \\
\end{tabular}
\end{center}
Tätä koodia käyttäen ei olisi mahdollista tietää,
tarkoittaako pakattu merkkijono 1011
merkkijonoa \texttt{AB} vai merkkijonoa \texttt{C}.
Using this code, it would not be possible to know
if the compressed string 1011 means
the string \texttt{AB} or the string \texttt{C}.
\index{Huffmanin koodaus}
\index{Huffman coding}
\subsubsection{Huffmanin koodaus}
\subsubsection{Huffman coding}
\key{Huffmanin koodaus} on ahne algoritmi,
joka muodostaa optimaalisen koodin
merkkijonon pakkaamista varten.
Se muodostaa merkkien esiintymiskertojen
perustella binääripuun, josta voi lukea
kunkin merkin koodisanan
liikkumalla huipulta merkkiä vastaavaan solmuun.
Liikkuminen vasemmalle vastaa
bittiä 0 ja liikkuminen oikealle
vastaa bittiä 1.
\key{Huffman coding} is a greedy algorithm
that constructs an optimal code for
compressing a string.
The algorithm builds a binary tree
based on the frequencies of the characters
in the string,
and a codeword for each characters can be read
by following a path from the root to
the corresponding node.
A move to the left correspons to bit 0,
and a move to the right corresponds to bit 1.
Aluksi jokaista merkkijonon merkkiä vastaa solmu,
jonka painona on merkin esiintymiskertojen määrä merkkijonossa.
Sitten joka vaiheessa puusta valitaan
kaksi painoltaan pienintä solmua
ja ne yhdistetään luomalla niiden
yläpuolelle uusi solmu,
jonka paino on solmujen yhteispaino.
Näin jatketaan, kunnes kaikki solmut
on yhdistetty ja koodi on valmis.
Initially, each character of the string is
represented by a node whose weight is the
number of times the character appears in the string.
Then at each step two nodes with minimum weights
are selected and they are combined by creating
a new node whose weight is the sum of the weights
of the original nodes.
The process continues until all nodes have been
combined and the code is ready.
Tarkastellaan nyt, miten Huffmanin koodaus
muodostaa optimaalisen koodin merkkijonolle
Next we will see how Huffman coding creates
the optimal code for the string
\texttt{AABACDACA}.
Alkutilanteessa on neljä solmua,
jotka vastaavat merkkijonossa olevia merkkejä:
Initially, there are four nodes that correspond
to the characters in the string:
\begin{center}
\begin{tikzpicture}[scale=0.9]
@ -570,13 +574,16 @@ jotka vastaavat merkkijonossa olevia merkkejä:
%\path[draw,thick,-] (4) -- (5);
\end{tikzpicture}
\end{center}
Merkkiä \texttt{A} vastaavan solmun paino on
5, koska merkki \texttt{A} esiintyy 5 kertaa merkkijonossa.
Muiden solmujen painot on laskettu vastaavalla tavalla.
The node that represents character \texttt{A}
has weight 5 because character \texttt{A}
appears 5 times in the string.
The other weights have been calculated
in the same way.
Ensimmäinen askel on yhdistää merkkejä \texttt{B} ja \texttt{D}
vastaavat solmut, joiden kummankin paino on 1.
Tuloksena on:
The first step is to combine the nodes that
correspond to characters \texttt{B} and \texttt{D},
both with weight 1.
The result is:
\begin{center}
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,0) {$5$};
@ -597,7 +604,7 @@ Tuloksena on:
\path[draw,thick,-] (4) -- (5);
\end{tikzpicture}
\end{center}
Tämän jälkeen yhdistetään solmut, joiden paino on 2:
After this, the nodes with weight 2 are combined:
\begin{center}
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (1,0) {$5$};
@ -623,7 +630,7 @@ Tämän jälkeen yhdistetään solmut, joiden paino on 2:
\path[draw,thick,-] (5) -- (6);
\end{tikzpicture}
\end{center}
Lopuksi yhdistetään kaksi viimeistä solmua:
Finally, the two remaining nodes are combined:
\begin{center}
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (2,2) {$5$};
@ -655,11 +662,11 @@ Lopuksi yhdistetään kaksi viimeistä solmua:
\end{tikzpicture}
\end{center}
Nyt kaikki solmut ovat puussa, joten koodi on valmis.
Puusta voidaan lukea seuraavat koodisanat:
Now all nodes are in the tree, so the code is ready.
The following codewords can be read from the tree:
\begin{center}
\begin{tabular}{rr}
merkki & koodisana \\
character & codeword \\
\hline
\texttt{A} & 0 \\
\texttt{B} & 110 \\