diff --git a/luku06.tex b/luku06.tex index a1c78df..9157887 100644 --- a/luku06.tex +++ b/luku06.tex @@ -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 \\