diff --git a/book.pdf b/book.pdf index 9d9113c..f4e19d6 100644 Binary files a/book.pdf and b/book.pdf differ diff --git a/book.tex b/book.tex index bdca2b8..464889f 100644 --- a/book.tex +++ b/book.tex @@ -1,6 +1,6 @@ \documentclass[twoside,12pt,a4paper,english]{book} -%\includeonly{luku01,kirj} +%\includeonly{chapter01,list} \usepackage[english]{babel} \usepackage[utf8]{inputenc} @@ -27,6 +27,8 @@ \usepackage{titlesec} +\usepackage{skak} + \usetikzlibrary{patterns,snakes} \pagestyle{plain} @@ -48,6 +50,7 @@ \author{\Large Antti Laaksonen} \makeindex +\usepackage[totoc]{idxlayout} \titleformat{\subsubsection} {\normalfont\large\bfseries\sffamily}{\thesubsection}{1em}{} @@ -64,7 +67,7 @@ \setcounter{tocdepth}{1} \tableofcontents -\include{johdanto} +\include{preface} \mainmatter \pagenumbering{arabic} @@ -73,41 +76,45 @@ \newcommand{\key}[1] {\textbf{#1}} \part{Basic techniques} -\include{luku01} -\include{luku02} -\include{luku03} -\include{luku04} -\include{luku05} -\include{luku06} -\include{luku07} -\include{luku08} -\include{luku09} -\include{luku10} +\include{chapter01} +\include{chapter02} +\include{chapter03} +\include{chapter04} +\include{chapter05} +\include{chapter06} +\include{chapter07} +\include{chapter08} +\include{chapter09} +\include{chapter10} \part{Graph algorithms} -\include{luku11} -\include{luku12} -\include{luku13} -\include{luku14} -\include{luku15} -\include{luku16} -\include{luku17} -\include{luku18} -\include{luku19} -\include{luku20} +\include{chapter11} +\include{chapter12} +\include{chapter13} +\include{chapter14} +\include{chapter15} +\include{chapter16} +\include{chapter17} +\include{chapter18} +\include{chapter19} +\include{chapter20} \part{Advanced topics} -\include{luku21} -\include{luku22} -\include{luku23} -\include{luku24} -\include{luku25} -\include{luku26} -\include{luku27} -\include{luku28} -\include{luku29} -\include{luku30} -\include{kirj} +\include{chapter21} +\include{chapter22} +\include{chapter23} +\include{chapter24} +\include{chapter25} +\include{chapter26} +\include{chapter27} +\include{chapter28} +\include{chapter29} +\include{chapter30} + +\cleardoublepage +\phantomsection +\addcontentsline{toc}{chapter}{Bibliography} +\include{list} \cleardoublepage \printindex -\end{document}la \ No newline at end of file +\end{document} \ No newline at end of file diff --git a/chapter01.tex b/chapter01.tex index d6037ce..1ce384a 100644 --- a/chapter01.tex +++ b/chapter01.tex @@ -117,10 +117,10 @@ but now it suffices to write \texttt{cout}. The code can be compiled using the following command: \begin{lstlisting} -g++ -std=c++11 -O2 -Wall code.cpp -o code +g++ -std=c++11 -O2 -Wall code.cpp -o bin \end{lstlisting} -This command produces a binary file \texttt{code} +This command produces a binary file \texttt{bin} from the source code \texttt{code.cpp}. The compiler follows the C++11 standard (\texttt{-std=c++11}), @@ -286,7 +286,7 @@ Still, it is good to know that the \texttt{g++} compiler also provides a 128-bit type \texttt{\_\_int128\_t} with a value range of -$-2^{127} \ldots 2^{127}-1$ or $-10^{38} \ldots 10^{38}$. +$-2^{127} \ldots 2^{127}-1$ or about $-10^{38} \ldots 10^{38}$. However, this type is not available in all contest systems. \subsubsection{Modular arithmetic} @@ -624,7 +624,7 @@ For example, in the above set New sets can be constructed using set operations: \begin{itemize} \item The \key{intersection} $A \cap B$ consists of elements -that are both in $A$ and $B$. +that are in both $A$ and $B$. For example, if $A=\{1,2,5\}$ and $B=\{2,4\}$, then $A \cap B = \{2\}$. \item The \key{union} $A \cup B$ consists of elements @@ -778,7 +778,9 @@ n! & = & n \cdot (n-1)! \\ \index{Fibonacci number} -The \key{Fibonacci numbers} arise in many situations. +The \key{Fibonacci numbers} +%\footnote{Fibonacci (c. 1175--1250) was an Italian mathematician.} +arise in many situations. They can be defined recursively as follows: \[ \begin{array}{lcl} @@ -790,7 +792,8 @@ f(n) & = & f(n-1)+f(n-2) \\ The first Fibonacci numbers are \[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, \ldots\] There is also a closed-form formula -for calculating Fibonacci numbers: +for calculating Fibonacci numbers\footnote{This formula is sometimes called +\index{Binet's formula} \key{Binet's formula}.}: \[f(n)=\frac{(1 + \sqrt{5})^n - (1-\sqrt{5})^n}{2^n \sqrt{5}}.\] \subsubsection{Logarithms} @@ -887,12 +890,13 @@ The International Collegiate Programming Contest (ICPC) is an annual programming contest for university students. Each team in the contest consists of three students, and unlike in the IOI, the students work together; -there is even only one computer available for each team. +there is only one computer available for each team. The ICPC consists of several stages, and finally the best teams are invited to the World Finals. While there are tens of thousands of participants -in the contest, there are only 128 final slots available, +in the contest, there are only a small number\footnote{The exact number of final +slots varies from year to year; in 2016, there were 128 final slots.} of final slots available, so even advancing to the finals is a great achievement in some regions. @@ -924,7 +928,7 @@ Google Code Jam and Yandex.Algorithm. Of course, companies also use those contests for recruiting: performing well in a contest is a good way to prove one's skills. -\section{Books} +\section{Resources} \subsubsection{Competitive programming books} @@ -933,12 +937,11 @@ concentrate on competitive programming and algorithmic problem solving: \begin{itemize} \item S. Halim and F. Halim: -\emph{Competitive Programming 3: The New Lower Bound of Programming Contests}, 2013 +\emph{Competitive Programming 3: The New Lower Bound of Programming Contests} \cite{hal13} \item S. S. Skiena and M. A. Revilla: -\emph{Programming Challenges: The Programming Contest Training Manual}, -Springer, 2003 -\item \emph{Looking for a Challenge? The Ultimate Problem Set from -the University of Warsaw Programming Competitions}, 2012 +\emph{Programming Challenges: The Programming Contest Training Manual} \cite{ski03} +\item K. Diks et al.: \emph{Looking for a Challenge? The Ultimate Problem Set from +the University of Warsaw Programming Competitions} \cite{dik12} \end{itemize} The first two books are intended for beginners, @@ -952,9 +955,9 @@ Some good books are: \begin{itemize} \item T. H. Cormen, C. E. Leiserson, R. L. Rivest and C. Stein: -\emph{Introduction to Algorithms}, MIT Press, 2009 (3rd edition) +\emph{Introduction to Algorithms} \cite{cor09} \item J. Kleinberg and É. Tardos: -\emph{Algorithm Design}, Pearson, 2005 +\emph{Algorithm Design} \cite{kle05} \item S. S. Skiena: -\emph{The Algorithm Design Manual}, Springer, 2008 (2nd edition) +\emph{The Algorithm Design Manual} \cite{ski08} \end{itemize} diff --git a/chapter02.tex b/chapter02.tex index 3ddd525..0c8e7da 100644 --- a/chapter02.tex +++ b/chapter02.tex @@ -281,7 +281,11 @@ Still, there are many important problems for which no polynomial algorithm is known, i.e., nobody knows how to solve them efficiently. \key{NP-hard} problems are an important set -of problems, for which no polynomial algorithm is known \cite{gar79}. +of problems, for which no polynomial algorithm +is known\footnote{A classic book on the topic is +M. R. Garey's and D. S. Johnson's +\emph{Computers and Intractability: A Guide to the Theory +of NP-Completeness} \cite{gar79}.}. \section{Estimating efficiency} @@ -309,15 +313,14 @@ assuming a time limit of one second. \begin{center} \begin{tabular}{ll} -input size ($n$) & required time complexity \\ +typical input size & required time complexity \\ \hline -$n \le 10^{18}$ & $O(1)$ or $O(\log n)$ \\ -$n \le 10^{12}$ & $O(\sqrt n)$ \\ -$n \le 10^6$ & $O(n)$ or $O(n \log n)$ \\ -$n \le 5000$ & $O(n^2)$ \\ -$n \le 500$ & $O(n^3)$ \\ -$n \le 25$ & $O(2^n)$ \\ $n \le 10$ & $O(n!)$ \\ +$n \le 20$ & $O(2^n)$ \\ +$n \le 500$ & $O(n^3)$ \\ +$n \le 5000$ & $O(n^2)$ \\ +$n \le 10^6$ & $O(n \log n)$ or $O(n)$ \\ +$n$ is large & $O(1)$ or $O(\log n)$ \\ \end{tabular} \end{center} @@ -353,8 +356,8 @@ time and even in $O(n)$ time. Given an array of $n$ integers $x_1,x_2,\ldots,x_n$, our task is to find the -\key{maximum subarray sum}\footnote{Bentley's -book \emph{Programming Pearls} \cite{ben86} made this problem popular.}, i.e., +\key{maximum subarray sum}\footnote{J. Bentley's +book \emph{Programming Pearls} \cite{ben86} made the problem popular.}, i.e., the largest possible sum of numbers in a contiguous region in the array. The problem is interesting when there may be @@ -444,8 +447,8 @@ and the sum of the numbers is calculated to the variable $s$. The variable $p$ contains the maximum sum found during the search. The time complexity of the algorithm is $O(n^3)$, -because it consists of three nested loops and -each loop contains $O(n)$ steps. +because it consists of three nested loops +that go through the input. \subsubsection{Algorithm 2} @@ -471,7 +474,9 @@ After this change, the time complexity is $O(n^2)$. \subsubsection{Algorithm 3} Surprisingly, it is possible to solve the problem -in $O(n)$ time, which means that we can remove +in $O(n)$ time\footnote{In \cite{ben86}, this linear-time algorithm +is attributed to J. B. Kadene, and the algorithm is sometimes +called \index{Kadene's algorithm} \key{Kadene's algorithm}.}, which means that we can remove one more loop. The idea is to calculate, for each array position, the maximum sum of a subarray that ends at that position. diff --git a/chapter03.tex b/chapter03.tex index 8a64d06..441ea1d 100644 --- a/chapter03.tex +++ b/chapter03.tex @@ -326,7 +326,8 @@ of the algorithm is at least $O(n^2)$. It is possible to sort an array efficiently in $O(n \log n)$ time using algorithms that are not limited to swapping consecutive elements. -One such algorithm is \key{mergesort} +One such algorithm is \key{mergesort}\footnote{According to \cite{knu983}, +mergesort was invented by J. von Neumann in 1945.} that is based on recursion. Mergesort sorts a subarray \texttt{t}$[a,b]$ as follows: @@ -538,8 +539,7 @@ but use some other information. An example of such an algorithm is \key{counting sort} that sorts an array in $O(n)$ time assuming that every element in the array -is an integer between $0 \ldots c$ where $c$ -is a small constant. +is an integer between $0 \ldots c$ and $c=O(n)$. The algorithm creates a \emph{bookkeeping} array whose indices are elements in the original array. diff --git a/chapter04.tex b/chapter04.tex index bf576c0..b0edcd9 100644 --- a/chapter04.tex +++ b/chapter04.tex @@ -196,7 +196,7 @@ for (auto x : s) { } \end{lstlisting} -An important property of sets +An important property of sets is that all the elements are \emph{distinct}. Thus, the function \texttt{count} always returns either 0 (the element is not in the set) @@ -723,7 +723,7 @@ $5 \cdot 10^6$ & $10{,}0$ s & $2{,}3$ s & $0{,}9$ s \\ \end{tabular} \end{center} -Algorithm 1 and 2 are equal except that +Algorithms 1 and 2 are equal except that they use different set structures. In this problem, this choice has an important effect on the running time, because algorithm 2 diff --git a/chapter05.tex b/chapter05.tex index fce1d21..56e946e 100644 --- a/chapter05.tex +++ b/chapter05.tex @@ -436,18 +436,18 @@ the $4 \times 4$ board are numbered as follows: \end{tikzpicture} \end{center} +Let $q(n)$ denote the number of ways +to place $n$ queens to te $n \times n$ chessboard. The above backtracking -algorithm tells us that -there are 92 ways to place 8 -queens to the $8 \times 8$ chessboard. +algorithm tells us that $q(n)=92$. When $n$ increases, the search quickly becomes slow, because the number of the solutions increases exponentially. -For example, calculating the ways to -place 16 queens to the $16 \times 16$ -chessboard already takes about a minute -on a modern computer -(there are 14772512 solutions). +For example, calculating $q(16)=14772512$ +using the above algorithm already takes about a minute +on a modern computer\footnote{There is no known way to efficiently +calculate larger values of $q(n)$. The current record is +$q(27)=234907967154122528$, calculated in 2016 \cite{q27}.}. \section{Pruning the search} @@ -716,7 +716,8 @@ check if the sum of any of the subsets is $x$. The running time of such a solution is $O(2^n)$, because there are $2^n$ subsets. However, using the meet in the middle technique, -we can achieve a more efficient $O(2^{n/2})$ time solution. +we can achieve a more efficient $O(2^{n/2})$ time solution\footnote{This +technique was introduced in 1974 by E. Horowitz and S. Sahni \cite{hor74}.}. Note that $O(2^n)$ and $O(2^{n/2})$ are different complexities because $2^{n/2}$ equals $\sqrt{2^n}$. diff --git a/chapter06.tex b/chapter06.tex index e4cb004..8b909af 100644 --- a/chapter06.tex +++ b/chapter06.tex @@ -103,8 +103,12 @@ is 6, the greedy algorithm produces the solution $4+1+1$ while the optimal solution is $3+3$. It is not known if the general coin problem -can be solved using any greedy algorithm. +can be solved using any greedy algorithm\footnote{However, it is possible +to \emph{check} in polynomial time +if the greedy algorithm presented in this chapter works for +a given set of coins \cite{pea05}.}. However, as we will see in Chapter 7, +in some cases, the general problem can be efficiently solved using a dynamic programming algorithm that always gives the @@ -530,7 +534,9 @@ the string \texttt{AB} or the string \texttt{C}. \subsubsection{Huffman coding} -\key{Huffman coding} \cite{huf52} is a greedy algorithm +\key{Huffman coding}\footnote{D. A. Huffman discovered this method +when solving a university course assignment +and published the algorithm in 1952 \cite{huf52}.} is a greedy algorithm that constructs an optimal code for compressing a given string. The algorithm builds a binary tree @@ -671,114 +677,4 @@ character & codeword \\ \texttt{C} & 10 \\ \texttt{D} & 111 \\ \end{tabular} -\end{center} - -% \subsubsection{Miksi algoritmi toimii?} -% -% Huffmanin koodaus on ahne algoritmi, koska se -% yhdistää aina kaksi solmua, joiden painot ovat -% pienimmät. -% Miksi on varmaa, että tämä menetelmä tuottaa -% aina optimaalisen koodin? -% -% Merkitään $c(x)$ merkin $x$ esiintymiskertojen -% määrää merkkijonossa sekä $s(x)$ -% merkkiä $x$ vastaavan koodisanan pituutta. -% Näitä merkintöjä käyttäen merkkijonon -% bittiesityksen pituus on -% \[\sum_x c(x) \cdot s(x),\] -% missä summa käy läpi kaikki merkkijonon merkit. -% Esimerkiksi äskeisessä esimerkissä -% bittiesityksen pituus on -% \[5 \cdot 1 + 1 \cdot 3 + 2 \cdot 2 + 1 \cdot 3 = 15.\] -% Hyödyllinen havainto on, että $s(x)$ on yhtä suuri kuin -% merkkiä $x$ vastaavan solmun \emph{syvyys} puussa -% eli matka puun huipulta solmuun. -% -% Perustellaan ensin, miksi optimaalista koodia vastaa -% aina binääripuu, jossa jokaisesta solmusta lähtee -% alaspäin joko kaksi haaraa tai ei yhtään haaraa. -% Tehdään vastaoletus, että jostain solmusta lähtisi -% alaspäin vain yksi haara. -% Esimerkiksi seuraavassa puussa tällainen tilanne on solmussa $a$: -% \begin{center} -% \begin{tikzpicture}[scale=0.9] -% \node[draw, circle, minimum size=20pt] (3) at (3,1) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (2) at (4,0) {$b$}; -% \node[draw, circle, minimum size=20pt] (5) at (5,1) {$a$}; -% \node[draw, circle, minimum size=20pt] (6) at (4,2) {\phantom{$a$}}; -% -% \path[draw,thick,-] (2) -- (5); -% \path[draw,thick,-] (3) -- (6); -% \path[draw,thick,-] (5) -- (6); -% \end{tikzpicture} -% \end{center} -% Tällainen solmu $a$ on kuitenkin aina turha, koska se -% tuo vain yhden bitin lisää polkuihin, jotka kulkevat -% solmun kautta, eikä sen avulla voi erottaa kahta -% koodisanaa toisistaan. Niinpä kyseisen solmun voi poistaa -% puusta, minkä seurauksena syntyy parempi koodi, -% eli optimaalista koodia vastaavassa puussa ei voi olla -% solmua, josta lähtee vain yksi haara. -% -% Perustellaan sitten, miksi on joka vaiheessa optimaalista -% yhdistää kaksi solmua, joiden painot ovat pienimmät. -% Tehdään vastaoletus, että solmun $a$ paino on pienin, -% mutta sitä ei saisi yhdistää aluksi toiseen solmuun, -% vaan sen sijasta tulisi yhdistää solmu $b$ -% ja jokin toinen solmu: -% \begin{center} -% \begin{tikzpicture}[scale=0.9] -% \node[draw, circle, minimum size=20pt] (1) at (0,0) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (2) at (-2,-1) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (3) at (2,-1) {$a$}; -% \node[draw, circle, minimum size=20pt] (4) at (-3,-2) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (5) at (-1,-2) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (8) at (-2,-3) {$b$}; -% \node[draw, circle, minimum size=20pt] (9) at (0,-3) {\phantom{$a$}}; -% -% \path[draw,thick,-] (1) -- (2); -% \path[draw,thick,-] (1) -- (3); -% \path[draw,thick,-] (2) -- (4); -% \path[draw,thick,-] (2) -- (5); -% \path[draw,thick,-] (5) -- (8); -% \path[draw,thick,-] (5) -- (9); -% \end{tikzpicture} -% \end{center} -% Solmuille $a$ ja $b$ pätee -% $c(a) \le c(b)$ ja $s(a) \le s(b)$. -% Solmut aiheuttavat bittiesityksen pituuteen lisäyksen -% \[c(a) \cdot s(a) + c(b) \cdot s(b).\] -% Tarkastellaan sitten toista tilannetta, -% joka on muuten samanlainen kuin ennen, -% mutta solmut $a$ ja $b$ on vaihdettu keskenään: -% \begin{center} -% \begin{tikzpicture}[scale=0.9] -% \node[draw, circle, minimum size=20pt] (1) at (0,0) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (2) at (-2,-1) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (3) at (2,-1) {$b$}; -% \node[draw, circle, minimum size=20pt] (4) at (-3,-2) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (5) at (-1,-2) {\phantom{$a$}}; -% \node[draw, circle, minimum size=20pt] (8) at (-2,-3) {$a$}; -% \node[draw, circle, minimum size=20pt] (9) at (0,-3) {\phantom{$a$}}; -% -% \path[draw,thick,-] (1) -- (2); -% \path[draw,thick,-] (1) -- (3); -% \path[draw,thick,-] (2) -- (4); -% \path[draw,thick,-] (2) -- (5); -% \path[draw,thick,-] (5) -- (8); -% \path[draw,thick,-] (5) -- (9); -% \end{tikzpicture} -% \end{center} -% Osoittautuu, että tätä puuta vastaava koodi on -% \emph{yhtä hyvä tai parempi} kuin alkuperäinen koodi, joten vastaoletus -% on väärin ja Huffmanin koodaus -% toimiikin oikein, jos se yhdistää aluksi solmun $a$ -% jonkin solmun kanssa. -% Tämän perustelee seuraava epäyhtälöketju: -% \[\begin{array}{rcl} -% c(b) & \ge & c(a) \\ -% c(b)\cdot(s(b)-s(a)) & \ge & c(a)\cdot (s(b)-s(a)) \\ -% c(b)\cdot s(b)-c(b)\cdot s(a) & \ge & c(a)\cdot s(b)-c(a)\cdot s(a) \\ -% c(a)\cdot s(a)+c(b)\cdot s(b) & \ge & c(a)\cdot s(b)+c(b)\cdot s(a) \\ -% \end{array}\] \ No newline at end of file +\end{center} \ No newline at end of file diff --git a/chapter07.tex b/chapter07.tex index 13de7b0..81ab5bc 100644 --- a/chapter07.tex +++ b/chapter07.tex @@ -708,7 +708,8 @@ depends on the values of the objects. \index{edit distance} \index{Levenshtein distance} -The \key{edit distance} or \key{Levenshtein distance} +The \key{edit distance} or \key{Levenshtein distance}\footnote{The distance +is named after V. I. Levenshtein who discussed it in connection with binary codes \cite{lev66}.} is the minimum number of editing operations needed to transform a string into another string. @@ -983,9 +984,10 @@ $2^m$ distinct rows and the time complexity is $O(n 2^{2m})$. As a final note, there is also a surprising direct formula -for calculating the number of tilings\footnote{Surprisingly, -this formula was discovered independently -by \cite{kas61} and \cite{tem61} in 1961.}: +for calculating the number of tilings: +% \footnote{Surprisingly, +% this formula was discovered independently +% by \cite{kas61} and \cite{tem61} in 1961.}: \[ \prod_{a=1}^{\lceil n/2 \rceil} \prod_{b=1}^{\lceil m/2 \rceil} 4 \cdot (\cos^2 \frac{\pi a}{n + 1} + \cos^2 \frac{\pi b}{m+1})\] This formula is very efficient, because it calculates the number of tilings in $O(nm)$ time, diff --git a/chapter09.tex b/chapter09.tex index 572e6aa..4a2fbf8 100644 --- a/chapter09.tex +++ b/chapter09.tex @@ -440,7 +440,8 @@ we can conclude that $\textrm{rmq}(2,7)=1$. \index{binary indexed tree} \index{Fenwick tree} -A \key{binary indexed tree} or \key{Fenwick tree} \cite{fen94} +A \key{binary indexed tree} or \key{Fenwick tree}\footnote{The +binary indexed tree structure was presented by P. M. Fenwick in 1994 \cite{fen94}.} can be seen as a dynamic version of a prefix sum array. This data structure supports two $O(\log n)$ time operations: calculating the sum of elements in a range @@ -738,7 +739,9 @@ takes $O(1)$ time using bit operations. \index{segment tree} -A \key{segment tree} is a data structure +A \key{segment tree}\footnote{The origin of this structure is unknown. +The bottom-up-implementation in this chapter corresponds to +the implementation in \cite{sta06}.} is a data structure that supports two operations: processing a range query and modifying an element in the array. diff --git a/chapter10.tex b/chapter10.tex index 13cce68..273e7c7 100644 --- a/chapter10.tex +++ b/chapter10.tex @@ -391,7 +391,8 @@ to change an iteration over permutations into an iteration over subsets, so that the dynamic programming state contains a subset of a set and possibly -some additional information. +some additional information\footnote{This technique was introduced in 1962 +by M. Held and R. M. Karp \cite{hel62}.}. The benefit in this is that $n!$, the number of permutations of an $n$ element set, diff --git a/chapter13.tex b/chapter13.tex index 12938d0..f6461be 100644 --- a/chapter13.tex +++ b/chapter13.tex @@ -24,7 +24,9 @@ for finding shortest paths. \index{Bellman–Ford algorithm} -The \key{Bellman–Ford algorithm} \cite{bel58} finds the +The \key{Bellman–Ford algorithm}\footnote{The algorithm is named after +R. E. Bellman and L. R. Ford who published it independently +in 1958 and 1956, respectively \cite{bel58,for56a}.} finds the shortest paths from a starting node to all other nodes in the graph. The algorithm can process all kinds of graphs, @@ -331,7 +333,9 @@ original Bellman–Ford algorithm. \index{Dijkstra's algorithm} -\key{Dijkstra's algorithm} \cite{dij59} finds the shortest +\key{Dijkstra's algorithm}\footnote{E. W. Dijkstra published the algorithm in 1959 \cite{dij59}; +however, his original paper does not mention how to implement the algorithm efficiently.} +finds the shortest paths from the starting node to all other nodes, like the Bellman–Ford algorithm. The benefit in Dijsktra's algorithm is that @@ -594,7 +598,9 @@ at most one distance to the priority queue. \index{Floyd–Warshall algorithm} -The \key{Floyd–Warshall algorithm} \cite{flo62} +The \key{Floyd–Warshall algorithm}\footnote{The algorithm +is named after R. W. Floyd and S. Warshall +who published it independently in 1962 \cite{flo62,war62}.} is an alternative way to approach the problem of finding shortest paths. Unlike the other algorihms in this chapter, diff --git a/chapter15.tex b/chapter15.tex index 4f7df84..4be2643 100644 --- a/chapter15.tex +++ b/chapter15.tex @@ -123,7 +123,8 @@ maximum spanning trees by processing the edges in reverse order. \index{Kruskal's algorithm} -In \key{Kruskal's algorithm} \cite{kru56}, the initial spanning tree +In \key{Kruskal's algorithm}\footnote{The algorithm was published in 1956 +by J. B. Kruskal \cite{kru56}.}, the initial spanning tree only contains the nodes of the graph and does not contain any edges. Then the algorithm goes through the edges @@ -409,7 +410,11 @@ belongs to more than one set. Two $O(\log n)$ time operations are supported: the \texttt{union} operation joins two sets, and the \texttt{find} operation finds the representative -of the set that contains a given element. +of the set that contains a given element\footnote{The structure presented here +was introduced in 1971 by J. D. Hopcroft and J. D. Ullman \cite{hop71}. +Later, in 1975, R. E. Tarjan studied a more sophisticated variant +of the structure \cite{tar75} that is discussed in many algorithm +textbooks nowadays.}. \subsubsection{Structure} @@ -567,7 +572,10 @@ the smaller set to the larger set. \index{Prim's algorithm} -\key{Prim's algorithm} \cite{pri57} is an alternative method +\key{Prim's algorithm}\footnote{The algorithm is +named after R. C. Prim who published it in 1957 \cite{pri57}. +However, the same algorithm was discovered already in 1930 +by V. Jarník.} is an alternative method for finding a minimum spanning tree. The algorithm first adds an arbitrary node to the tree. diff --git a/chapter16.tex b/chapter16.tex index f5e312d..09d99cb 100644 --- a/chapter16.tex +++ b/chapter16.tex @@ -657,7 +657,9 @@ achieves these properties. \index{Floyd's algorithm} -\key{Floyd's algorithm} walks forward +\key{Floyd's algorithm}\footnote{The idea of the algorithm is mentioned in \cite{knu982} +and attributed to R. W. Floyd; however, it is not known if Floyd was the first +who discovered the algorithm.} walks forward in the graph using two pointers $a$ and $b$. Both pointers begin at a node $x$ that is the starting node of the graph. diff --git a/chapter17.tex b/chapter17.tex index ba99272..b52dad6 100644 --- a/chapter17.tex +++ b/chapter17.tex @@ -368,7 +368,10 @@ performs two depth-first searches. \index{2SAT problem} Strongly connectivity is also linked with the -\key{2SAT problem} \cite{asp79}. +\key{2SAT problem}\footnote{The algorithm presented here was +introduced in \cite{asp79}. +There is also another well-known linear-time algorithm \cite{eve75} +that is based on backtracking.}. In this problem, we are given a logical formula \[ (a_1 \lor b_1) \land (a_2 \lor b_2) \land \cdots \land (a_m \lor b_m), diff --git a/chapter18.tex b/chapter18.tex index 309f2c1..81c7ab3 100644 --- a/chapter18.tex +++ b/chapter18.tex @@ -266,14 +266,18 @@ is $3+4+3+1=11$. \end{center} The idea is to construct a tree traversal array that contains -three values for each node: (1) the identifier of the node, -(2) the size of the subtree, and (3) the value of the node. +three values for each node: the identifier of the node, +the size of the subtree, and the value of the node. For example, the array for the above tree is as follows: \begin{center} \begin{tikzpicture}[scale=0.7] \draw (0,1) grid (9,-2); +\node[left] at (-1,0.5) {node id}; +\node[left] at (-1,-0.5) {subtree size}; +\node[left] at (-1,-1.5) {node value}; + \node at (0.5,0.5) {$1$}; \node at (1.5,0.5) {$2$}; \node at (2.5,0.5) {$6$}; @@ -330,6 +334,10 @@ can be found as follows: \fill[color=lightgray] (4,-1) rectangle (8,-2); \draw (0,1) grid (9,-2); +\node[left] at (-1,0.5) {node id}; +\node[left] at (-1,-0.5) {subtree size}; +\node[left] at (-1,-1.5) {node value}; + \node at (0.5,0.5) {$1$}; \node at (1.5,0.5) {$2$}; \node at (2.5,0.5) {$6$}; @@ -438,6 +446,10 @@ For example, the following array corresponds to the above tree: \begin{tikzpicture}[scale=0.7] \draw (0,1) grid (9,-2); +\node[left] at (-1,0.5) {node id}; +\node[left] at (-1,-0.5) {subtree size}; +\node[left] at (-1,-1.5) {path sum}; + \node at (0.5,0.5) {$1$}; \node at (1.5,0.5) {$2$}; \node at (2.5,0.5) {$6$}; @@ -491,6 +503,10 @@ the array changes as follows: \fill[color=lightgray] (4,-1) rectangle (8,-2); \draw (0,1) grid (9,-2); +\node[left] at (-1,0.5) {node id}; +\node[left] at (-1,-0.5) {subtree size}; +\node[left] at (-1,-1.5) {path sum}; + \node at (0.5,0.5) {$1$}; \node at (1.5,0.5) {$2$}; \node at (2.5,0.5) {$6$}; @@ -562,9 +578,9 @@ is node 2: \node[draw, circle] (3) at (-2,1) {$2$}; \node[draw, circle] (4) at (0,1) {$3$}; \node[draw, circle] (5) at (2,-1) {$7$}; -\node[draw, circle] (6) at (-3,-1) {$5$}; +\node[draw, circle, fill=lightgray] (6) at (-3,-1) {$5$}; \node[draw, circle] (7) at (-1,-1) {$6$}; -\node[draw, circle] (8) at (-1,-3) {$8$}; +\node[draw, circle, fill=lightgray] (8) at (-1,-3) {$8$}; \path[draw,thick,-] (1) -- (2); \path[draw,thick,-] (1) -- (3); \path[draw,thick,-] (1) -- (4); @@ -572,6 +588,9 @@ is node 2: \path[draw,thick,-] (3) -- (6); \path[draw,thick,-] (3) -- (7); \path[draw,thick,-] (7) -- (8); + +\path[draw=red,thick,->,line width=2pt] (6) edge [bend left] (3); +\path[draw=red,thick,->,line width=2pt] (8) edge [bend right=40] (3); \end{tikzpicture} \end{center} @@ -583,13 +602,17 @@ finding the lowest common ancestor of two nodes. One way to solve the problem is to use the fact that we can efficiently find the $k$th ancestor of any node in the tree. -Thus, we can first make sure that -both nodes are at the same level in the tree, -and then find the smallest value of $k$ -such that the $k$th ancestor of both nodes is the same. +Using this, we can divide the problem of +finding the lowest common ancestor into two parts. -As an example, let us find the lowest common -ancestor of nodes $5$ and $8$: +We use two pointers that initially point to the +two nodes for which we should find the +lowest common ancestor. +First, we move one of the pointers upwards +so that both nodes are at the same level in the tree. + +In the example case, we move from node 8 to node 6, +after which both nodes are at the same level: \begin{center} \begin{tikzpicture}[scale=0.9] @@ -599,8 +622,8 @@ ancestor of nodes $5$ and $8$: \node[draw, circle] (4) at (0,1) {$3$}; \node[draw, circle] (5) at (2,-1) {$7$}; \node[draw, circle,fill=lightgray] (6) at (-3,-1) {$5$}; -\node[draw, circle] (7) at (-1,-1) {$6$}; -\node[draw, circle,fill=lightgray] (8) at (-1,-3) {$8$}; +\node[draw, circle,fill=lightgray] (7) at (-1,-1) {$6$}; +\node[draw, circle] (8) at (-1,-3) {$8$}; \path[draw,thick,-] (1) -- (2); \path[draw,thick,-] (1) -- (3); \path[draw,thick,-] (1) -- (4); @@ -608,26 +631,30 @@ ancestor of nodes $5$ and $8$: \path[draw,thick,-] (3) -- (6); \path[draw,thick,-] (3) -- (7); \path[draw,thick,-] (7) -- (8); + +\path[draw=red,thick,->,line width=2pt] (8) edge [bend right] (7); \end{tikzpicture} \end{center} -Node $5$ is at level $3$, while node $8$ is at level $4$. -Thus, we first move one step upwards from node $8$ to node $6$. -After this, it turns out that the parent of both nodes $5$ -and $6$ is node $2$, so we have found the lowest common ancestor. +After this, we determine the minimum number of steps +needed to move both pointers upwards so that +they will point to the same node. +This node is the lowest common ancestor of the nodes. -The following picture shows how we move in the tree: +In the example case, it suffices to move both pointers +one step upwards to node 2, +which is the lowest common ancestor: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (0,3) {$1$}; \node[draw, circle] (2) at (2,1) {$4$}; -\node[draw, circle] (3) at (-2,1) {$2$}; +\node[draw, circle,fill=lightgray] (3) at (-2,1) {$2$}; \node[draw, circle] (4) at (0,1) {$3$}; \node[draw, circle] (5) at (2,-1) {$7$}; -\node[draw, circle,fill=lightgray] (6) at (-3,-1) {$5$}; +\node[draw, circle] (6) at (-3,-1) {$5$}; \node[draw, circle] (7) at (-1,-1) {$6$}; -\node[draw, circle,fill=lightgray] (8) at (-1,-3) {$8$}; +\node[draw, circle] (8) at (-1,-3) {$8$}; \path[draw,thick,-] (1) -- (2); \path[draw,thick,-] (1) -- (3); \path[draw,thick,-] (1) -- (4); @@ -637,20 +664,21 @@ The following picture shows how we move in the tree: \path[draw,thick,-] (7) -- (8); \path[draw=red,thick,->,line width=2pt] (6) edge [bend left] (3); -\path[draw=red,thick,->,line width=2pt] (8) edge [bend right] (7); \path[draw=red,thick,->,line width=2pt] (7) edge [bend right] (3); \end{tikzpicture} \end{center} -Using this method, we can find the lowest common ancestor -of any two nodes in $O(\log n)$ time after an $O(n \log n)$ time -preprocessing, because both steps can be -performed in $O(\log n)$ time. +Since both parts of the algorithm can be performed in +$O(\log n)$ time using precomputed information, +we can find the lowest common ancestor of any two +nodes in $O(\log n)$ time using this technique. \subsubsection{Method 2} Another way to solve the problem is based on -a tree traversal array \cite{ben00}. +a tree traversal array\footnote{This lowest common ancestor algorithm is based on \cite{ben00}. +This technique is sometimes called the \index{Euler tour technique} +\key{Euler tour technique} \cite{tar84}.}. Once again, the idea is to traverse the nodes using a depth-first search: @@ -689,23 +717,26 @@ using a depth-first search: \end{tikzpicture} \end{center} -However, we use a bit different variant of -the tree traversal array where +However, we use a bit different tree +traversal array than before: we add each node to the array \emph{always} -when the depth-first search visits the node, +when the depth-first search walks through the node, and not only at the first visit. Hence, a node that has $k$ children appears $k+1$ times -in the array, and there are a total of $2n-1$ +in the array and there are a total of $2n-1$ nodes in the array. We store two values in the array: -(1) the identifier of the node, and (2) the level of the +the identifier of the node and the level of the node in the tree. The following array corresponds to the above tree: \begin{center} \begin{tikzpicture}[scale=0.7] +\node[left] at (-1,1.5) {node id}; +\node[left] at (-1,0.5) {level}; + \draw (0,1) grid (15,2); %\node at (-1.1,1.5) {\texttt{node}}; \node at (0.5,1.5) {$1$}; @@ -770,6 +801,10 @@ can be found as follows: \begin{center} \begin{tikzpicture}[scale=0.7] + +\node[left] at (-1,1.5) {node id}; +\node[left] at (-1,0.5) {level}; + \fill[color=lightgray] (2,1) rectangle (3,2); \fill[color=lightgray] (5,1) rectangle (6,2); \fill[color=lightgray] (2,0) rectangle (6,1); diff --git a/chapter19.tex b/chapter19.tex index 7654741..d000a7e 100644 --- a/chapter19.tex +++ b/chapter19.tex @@ -22,7 +22,9 @@ problem and no efficient algorithm is known for solving the problem. \index{Eulerian path} -An \key{Eulerian path} is a path +An \key{Eulerian path}\footnote{L. Euler (1707--1783) studied such paths in 1736 +when he solved the famous Königsberg bridge problem. +This was the birth of graph theory.} is a path that goes exactly once through each edge in the graph. For example, the graph \begin{center} @@ -222,7 +224,8 @@ from node 2 to node 5: \index{Hierholzer's algorithm} -\key{Hierholzer's algorithm} is an efficient +\key{Hierholzer's algorithm}\footnote{The algorithm was published +in 1873 after Hierholzer's death \cite{hie73}.} is an efficient method for constructing an Eulerian circuit. The algorithm consists of several rounds, @@ -395,7 +398,9 @@ so we have successfully constructed an Eulerian circuit. \index{Hamiltonian path} -A \key{Hamiltonian path} is a path +A \key{Hamiltonian path} +%\footnote{W. R. Hamilton (1805--1865) was an Irish mathematician.} +is a path that visits each node in the graph exactly once. For example, the graph \begin{center} @@ -481,12 +486,12 @@ Also stronger results have been achieved: \begin{itemize} \item \index{Dirac's theorem} -\key{Dirac's theorem}: +\key{Dirac's theorem}: %\cite{dir52} If the degree of each node is at least $n/2$, the graph contains a Hamiltonian path. \item \index{Ore's theorem} -\key{Ore's theorem}: +\key{Ore's theorem}: %\cite{ore60} If the sum of degrees of each non-adjacent pair of nodes is at least $n$, the graph contains a Hamiltonian path. @@ -525,7 +530,9 @@ It is possible to implement this solution in $O(2^n n^2)$ time. \index{De Bruijn sequence} -A \key{De Bruijn sequence} is a string that contains +A \key{De Bruijn sequence} +%\footnote{N. G. de Bruijn (1918--2012) was a Dutch mathematician.} +is a string that contains every string of length $n$ exactly once as a substring, for a fixed alphabet of $k$ characters. @@ -546,7 +553,7 @@ and each edge adds one character to the string. The following graph corresponds to the above example: \begin{center} -\begin{tikzpicture} +\begin{tikzpicture}[scale=0.8] \node[draw, circle] (00) at (-3,0) {00}; \node[draw, circle] (11) at (3,0) {11}; \node[draw, circle] (01) at (0,2) {01}; @@ -628,12 +635,13 @@ The search can be made more efficient by using \key{heuristics} that attempt to guide the knight so that a complete tour will be found quickly. -\subsubsection{Warnsdorff's rule} +\subsubsection{Warnsdorf's rule} \index{heuristic} -\index{Warnsdorff's rule} +\index{Warnsdorf's rule} -\key{Warnsdorff's rule} is a simple and effective heuristic +\key{Warnsdorf's rule}\footnote{This heuristic was proposed +in Warnsdorf's book \cite{war23} in 1823.} is a simple and effective heuristic for finding a knight's tour. Using the rule, it is possible to efficiently construct a tour even on a large board. @@ -655,7 +663,7 @@ possible squares to which the knight can move: \node at (3.5,1.5) {$d$}; \end{tikzpicture} \end{center} -In this situation, Warnsdorff's rule moves the knight to square $a$, +In this situation, Warnsdorf's rule moves the knight to square $a$, because after this choice, there is only a single possible move. The other choices would move the knight to squares where there would be three moves available. diff --git a/chapter21.tex b/chapter21.tex index ebd31d4..7f2d221 100644 --- a/chapter21.tex +++ b/chapter21.tex @@ -24,7 +24,7 @@ z = \sqrt[3]{3}.\\ However, nobody knows if there are any three \emph{integers} $x$, $y$ and $z$ that would satisfy the equation, but this -is an open problem in number theory. +is an open problem in number theory \cite{bec07}. In this chapter, we will focus on basic concepts and algorithms in number theory. @@ -205,7 +205,9 @@ so the result of the function is $[2,2,2,3]$. \index{sieve of Eratosthenes} -The \key{sieve of Eratosthenes} is a preprocessing +The \key{sieve of Eratosthenes} +%\footnote{Eratosthenes (c. 276 BC -- c. 194 BC) was a Greek mathematician.} +is a preprocessing algorithm that builds an array using which we can efficiently check if a given number between $2 \ldots n$ is prime and, if it is not, find one prime factor of the number. @@ -327,7 +329,8 @@ The greatest common divisor and the least common multiple are connected as follows: \[\textrm{lcm}(a,b)=\frac{ab}{\textrm{gcd}(a,b)}\] -\key{Euclid's algorithm} provides an efficient way +\key{Euclid's algorithm}\footnote{Euclid was a Greek mathematician who +lived in about 300 BC. This is perhaps the first known algorithm in history.} provides an efficient way to find the greatest common divisor of two numbers. The algorithm is based on the following formula: \begin{equation*} @@ -355,6 +358,7 @@ For example, Numbers $a$ and $b$ are \key{coprime} if $\textrm{gcd}(a,b)=1$. \key{Euler's totient function} $\varphi(n)$ +%\footnote{Euler presented this function in 1763.} gives the number of coprime numbers to $n$ between $1$ and $n$. For example, $\varphi(12)=4$, @@ -432,12 +436,16 @@ int modpow(int x, int n, int m) { \index{Fermat's theorem} \index{Euler's theorem} -\key{Fermat's theorem} states that +\key{Fermat's theorem} +%\footnote{Fermat discovered this theorem in 1640.} +states that \[x^{m-1} \bmod m = 1\] when $m$ is prime and $x$ and $m$ are coprime. This also yields \[x^k \bmod m = x^{k \bmod (m-1)} \bmod m.\] -More generally, \key{Euler's theorem} states that +More generally, \key{Euler's theorem} +%\footnote{Euler published this theorem in 1763.} +states that \[x^{\varphi(m)} \bmod m = 1\] when $x$ and $m$ are coprime. Fermat's theorem follows from Euler's theorem, @@ -517,7 +525,9 @@ cout << x*x << "\n"; // 2537071545 \index{Diophantine equation} -A \key{Diophantine equation} is an equation of the form +A \key{Diophantine equation} +%\footnote{Diophantus of Alexandria was a Greek mathematician who lived in the 3th century.} +is an equation of the form \[ ax + by = c, \] where $a$, $b$ and $c$ are constants and we should find the values of $x$ and $y$. @@ -637,7 +647,9 @@ are solutions. \index{Lagrange's theorem} -\key{Lagrange's theorem} states that every positive integer +\key{Lagrange's theorem} +%\footnote{J.-L. Lagrange (1736--1813) was an Italian mathematician.} +states that every positive integer can be represented as a sum of four squares, i.e., $a^2+b^2+c^2+d^2$. For example, the number 123 can be represented @@ -648,7 +660,9 @@ as the sum $8^2+5^2+5^2+3^2$. \index{Zeckendorf's theorem} \index{Fibonacci number} -\key{Zeckendorf's theorem} states that every +\key{Zeckendorf's theorem} +%\footnote{E. Zeckendorf published the theorem in 1972 \cite{zec72}; however, this was not a new result.} +states that every positive integer has a unique representation as a sum of Fibonacci numbers such that no two numbers are equal or consecutive @@ -689,7 +703,9 @@ produces the smallest Pythagorean triple \index{Wilson's theorem} -\key{Wilson's theorem} states that a number $n$ +\key{Wilson's theorem} +%\footnote{J. Wilson (1741--1793) was an English mathematician.} +states that a number $n$ is prime exactly when \[(n-1)! \bmod n = n-1.\] For example, the number 11 is prime, because diff --git a/chapter22.tex b/chapter22.tex index e6fb642..676f857 100644 --- a/chapter22.tex +++ b/chapter22.tex @@ -342,7 +342,9 @@ corresponds to the binomial coefficient formula. \index{Catalan number} -The \key{Catalan number} $C_n$ equals the +The \key{Catalan number} +%\footnote{E. C. Catalan (1814--1894) was a Belgian mathematician.} +$C_n$ equals the number of valid parenthesis expressions that consist of $n$ left parentheses and $n$ right parentheses. @@ -678,7 +680,9 @@ elements should be changed. \index{Burnside's lemma} -\key{Burnside's lemma} can be used to count +\key{Burnside's lemma} +%\footnote{Actually, Burnside did not discover this lemma; he only mentioned it in his book \cite{bur97}.} +can be used to count the number of combinations so that only one representative is counted for each group of symmetric combinations. @@ -764,7 +768,10 @@ with 3 colors is \index{Cayley's formula} -\key{Cayley's formula} states that +\key{Cayley's formula} +% \footnote{While the formula is named after A. Cayley, +% who studied it in 1889, it was discovered earlier by C. W. Borchardt in 1860.} +states that there are $n^{n-2}$ labeled trees that contain $n$ nodes. The nodes are labeled $1,2,\ldots,n$, @@ -827,7 +834,9 @@ be derived using Prüfer codes. \index{Prüfer code} -A \key{Prüfer code} is a sequence of +A \key{Prüfer code} +%\footnote{In 1918, H. Prüfer proved Cayley's theorem using Prüfer codes \cite{pru18}.} +is a sequence of $n-2$ numbers that describes a labeled tree. The code is constructed by following a process that removes $n-2$ leaves from the tree. diff --git a/chapter23.tex b/chapter23.tex index 82d27f6..b4d6c25 100644 --- a/chapter23.tex +++ b/chapter23.tex @@ -245,8 +245,9 @@ two $n \times n$ matrices in $O(n^3)$ time. There are also more efficient algorithms for matrix multiplication\footnote{The first such -algorithm, with time complexity $O(n^{2.80735})$, -was published in 1969 \cite{str69}, and +algorithm was Strassen's algorithm, +published in 1969 \cite{str69}, +whose time complexity is $O(n^{2.80735})$; the best current algorithm works in $O(n^{2.37286})$ time \cite{gal14}.}, but they are mostly of theoretical interest @@ -749,7 +750,9 @@ $2 \rightarrow 1 \rightarrow 4 \rightarrow 2 \rightarrow 5$. \index{Kirchhoff's theorem} \index{spanning tree} -\key{Kirchhoff's theorem} provides a way +\key{Kirchhoff's theorem} +%\footnote{G. R. Kirchhoff (1824--1887) was a German physicist.} +provides a way to calculate the number of spanning trees of a graph as a determinant of a special matrix. For example, the graph diff --git a/chapter24.tex b/chapter24.tex index a4bd1aa..a739613 100644 --- a/chapter24.tex +++ b/chapter24.tex @@ -359,7 +359,10 @@ The expected value for $X$ in a geometric distribution is \index{Markov chain} -A \key{Markov chain} is a random process +A \key{Markov chain} +% \footnote{A. A. Markov (1856--1922) +% was a Russian mathematician.} +is a random process that consists of states and transitions between them. For each state, we know the probabilities for moving to other states. @@ -514,7 +517,11 @@ just to find one element? It turns out that we can find order statistics using a randomized algorithm without sorting the array. -The algorithm is a Las Vegas algorithm: +The algorithm, called \key{quickselect}\footnote{In 1961, +C. A. R. Hoare published two algorithms that +are efficient on average: \index{quicksort} \index{quickselect} +\key{quicksort} \cite{hoa61a} for sorting arrays and +\key{quickselect} \cite{hoa61b} for finding order statistics.}, is a Las Vegas algorithm: its running time is usually $O(n)$ but $O(n^2)$ in the worst case. @@ -560,7 +567,9 @@ but one could hope that verifying the answer would by easier than to calculate it from scratch. It turns out that we can solve the problem -using a Monte Carlo algorithm whose +using a Monte Carlo algorithm\footnote{R. M. Freivalds published +this algorithm in 1977 \cite{fre77}, and it is sometimes +called \index{Freivalds' algoritm} \key{Freivalds' algorithm}.} whose time complexity is only $O(n^2)$. The idea is simple: we choose a random vector $X$ of $n$ elements, and calculate the matrices diff --git a/chapter25.tex b/chapter25.tex index 5c3b9dc..a34227f 100644 --- a/chapter25.tex +++ b/chapter25.tex @@ -248,7 +248,8 @@ and this is always the final state. It turns out that we can easily classify any nim state by calculating the \key{nim sum} $x_1 \oplus x_2 \oplus \cdots \oplus x_n$, -where $\oplus$ is the xor operation. +where $\oplus$ is the xor operation\footnote{The optimal strategy +for nim was published in 1901 by C. L. Bouton \cite{bou01}.}. The states whose nim sum is 0 are losing states, and all other states are winning states. For example, the nim sum for @@ -367,7 +368,8 @@ so the nim sum is not 0. \index{Sprague–Grundy theorem} -The \key{Sprague–Grundy theorem} generalizes the +The \key{Sprague–Grundy theorem}\footnote{The theorem was discovered +independently by R. Sprague \cite{spr35} and P. M. Grundy \cite{gru39}.} generalizes the strategy used in nim to all games that fulfil the following requirements: diff --git a/chapter29.tex b/chapter29.tex index 2a872b2..d83f0c8 100644 --- a/chapter29.tex +++ b/chapter29.tex @@ -42,6 +42,7 @@ After this, it suffices to sum the areas of the triangles. The area of a triangle can be calculated, for example, using \key{Heron's formula} +%\footnote{Heron of Alexandria (c. 10--70) was a Greek mathematician.} \[ \sqrt{s (s-a) (s-b) (s-c)},\] where $a$, $b$ and $c$ are the lengths of the triangle's sides and @@ -500,7 +501,8 @@ so $b$ is outside the polygon. \section{Polygon area} A general formula for calculating the area -of a polygon is +of a polygon\footnote{This formula is sometimes called the +\index{shoelace formula} \key{shoelace formula}.} is \[\frac{1}{2} |\sum_{i=1}^{n-1} (p_i \times p_{i+1})| = \frac{1}{2} |\sum_{i=1}^{n-1} (x_i y_{i+1} - x_{i+1} y_i)|, \] where the vertices are diff --git a/chapter30.tex b/chapter30.tex index c582e2a..17e3e6b 100644 --- a/chapter30.tex +++ b/chapter30.tex @@ -27,10 +27,10 @@ For example, the table \begin{tabular}{ccc} person & arrival time & leaving time \\ \hline -Uolevi & 10 & 15 \\ -Maija & 6 & 12 \\ -Kaaleppi & 14 & 16 \\ -Liisa & 5 & 13 \\ +John & 10 & 15 \\ +Maria & 6 & 12 \\ +Peter & 14 & 16 \\ +Lisa & 5 & 13 \\ \end{tabular} \end{center} corresponds to the following events: @@ -51,10 +51,10 @@ corresponds to the following events: \draw[fill] (5,-5.5) circle [radius=0.05]; \draw[fill] (13,-5.5) circle [radius=0.05]; -\node at (2,-1) {Uolevi}; -\node at (2,-2.5) {Maija}; -\node at (2,-4) {Kaaleppi}; -\node at (2,-5.5) {Liisa}; +\node at (2,-1) {John}; +\node at (2,-2.5) {Maria}; +\node at (2,-4) {Peter}; +\node at (2,-5.5) {Lisa}; \end{tikzpicture} \end{center} We go through the events from left to right @@ -85,10 +85,10 @@ In the example, the events are processed as follows: \draw[fill] (5,-5.5) circle [radius=0.05]; \draw[fill] (13,-5.5) circle [radius=0.05]; -\node at (2,-1) {Uolevi}; -\node at (2,-2.5) {Maija}; -\node at (2,-4) {Kaaleppi}; -\node at (2,-5.5) {Liisa}; +\node at (2,-1) {John}; +\node at (2,-2.5) {Maria}; +\node at (2,-4) {Peter}; +\node at (2,-5.5) {Lisa}; \path[draw,dashed] (10,0)--(10,-6.5); \path[draw,dashed] (15,0)--(15,-6.5); @@ -122,7 +122,7 @@ The symbols $+$ and $-$ indicate whether the value of the counter increases or decreases, and the value of the counter is shown below. The maximum value of the counter is 3 -between Uolevi's arrival time and Maija's leaving time. +between John's arrival time and Maria's leaving time. The running time of the algorithm is $O(n \log n)$, because sorting the events takes $O(n \log n)$ time @@ -270,7 +270,11 @@ we should find the following points: This is another example of a problem that can be solved in $O(n \log n)$ time -using a sweep line algorithm. +using a sweep line algorithm\footnote{Besides this approach, +there is also an +$O(n \log n)$ time divide-and-conquer algorithm \cite{sha75} +that divides the points into two sets and recursively +solves the problem for both sets.}. We go through the points from left to right and maintain a value $d$: the minimum distance between two points seen so far. @@ -396,21 +400,20 @@ an easy way to construct the convex hull for a set of points in $O(n \log n)$ time. The algorithm constructs the convex hull -in two steps: +in two parts: first the upper hull and then the lower hull. -Both steps are similar, so we can focus on +Both parts are similar, so we can focus on constructing the upper hull. -We sort the points primarily according to +First, we sort the points primarily according to x coordinates and secondarily according to y coordinates. -After this, we go through the points and always -add the new point to the hull. -After adding a point we check using cross products -whether the tree last point in the hull turn left. -If this holds, we remove the middle point from the hull. -After this we keep checking the three last points -and removing points, until the three last points -do not turn left. +After this, we go through the points and +add each point to the hull. +Always after adding a point to the hull, +we make sure that the last line segment +in the hull does not turn left. +As long as this holds, we repeatedly remove the +second last point from the hull. The following pictures show how Andrew's algorithm works: diff --git a/list.tex b/list.tex index 6cd1b06..8939e38 100644 --- a/list.tex +++ b/list.tex @@ -25,6 +25,11 @@ On a routing problem. \emph{Quarterly of Applied Mathematics}, 16(1):87--90, 1958. +\bibitem{bec07} + M. Beck, E. Pine, W. Tarrat and K. Y. Jensen. + New integer representations as the sum of three cubes. + \emph{Mathematics of Computation}, 76(259):1683--1690, 2007. + \bibitem{ben00} M. A. Bender and M. Farach-Colton. The LCA problem revisited. In @@ -33,17 +38,46 @@ \bibitem{ben86} J. Bentley. \emph{Programming Pearls}. - Addison-Wesley, 1986. + Addison-Wesley, 1999 (2nd edition). + +\bibitem{bou01} + C. L. Bouton. + Nim, a game with a complete mathematical theory. +pro \emph{Annals of Mathematics}, 3(1/4):35--39, 1901. + +% \bibitem{bur97} +% W. Burnside. +% \emph{Theory of Groups of Finite Order}, +% Cambridge University Press, 1897. \bibitem{cod15} Codeforces: On ''Mo's algorithm'', \url{http://codeforces.com/blog/entry/20032} +\bibitem{cor09} + T. H. Cormen, C. E. Leiserson, R. L. Rivest and C. Stein. + \emph{Introduction to Algorithms}, MIT Press, 2009 (3rd edition). + \bibitem{dij59} E. W. Dijkstra. A note on two problems in connexion with graphs. \emph{Numerische Mathematik}, 1(1):269--271, 1959. +\bibitem{dik12} + K. Diks et al. + \emph{Looking for a Challenge? The Ultimate Problem Set from + the University of Warsaw Programming Competitions}, University of Warsaw, 2012. + +% \bibitem{dil50} +% R. P. Dilworth. +% A decomposition theorem for partially ordered sets. +% \emph{Annals of Mathematics}, 51(1):161--166, 1950. + +% \bibitem{dir52} +% G. A. Dirac. +% Some theorems on abstract graphs. +% \emph{Proceedings of the London Mathematical Society}, 3(1):69--81, 1952. + \bibitem{edm65} J. Edmonds. Paths, trees, and flowers. @@ -54,6 +88,11 @@ Theoretical improvements in algorithmic efficiency for network flow problems. \emph{Journal of the ACM}, 19(2):248--264, 1972. +\bibitem{eve75} + S. Even, A. Itai and A. Shamir. + On the complexity of time table and multi-commodity flow problems. + \emph{16th Annual Symposium on Foundations of Computer Science}, 184--193, 1975. + \bibitem{fan94} D. Fanding. A faster algorithm for shortest-path -- SPFA. @@ -69,21 +108,26 @@ Theoretical and practical improvements on the RMQ-problem, with applications to LCA and LCE. In \emph{Annual Symposium on Combinatorial Pattern Matching}, 36--48, 2006. -\bibitem{fis11} - J. Fischer and V. Heun. - Space-efficient preprocessing schemes for range minimum queries on static arrays. - \emph{SIAM Journal on Computing}, 40(2):465--492, 2011. - \bibitem{flo62} R. W. Floyd Algorithm 97: shortest path. \emph{Communications of the ACM}, 5(6):345, 1962. +\bibitem{for56a} + L. R. Ford. + Network flow theory. + RAND Corporation, Santa Monica, California, 1956. + \bibitem{for56} L. R. Ford and D. R. Fulkerson. Maximal flow through a network. \emph{Canadian Journal of Mathematics}, 8(3):399--404, 1956. +\bibitem{fre77} + R. Freivalds. + Probabilistic machines can use less running time. + In \emph{IFIP congress}, 839--842, 1977. + \bibitem{gal14} F. Le Gall. Powers of tensors and fast matrix multiplication. @@ -106,13 +150,58 @@ \emph{2014 IEEE 55th Annual Symposium on Foundations of Computer Science}, 621--630, 2014. +\bibitem{gru39} + P. M. Grundy. + Mathematics and games. + \emph{Eureka}, 2(5):6--8, 1939. + \bibitem{gus97} D. Gusfield. \emph{Algorithms on Strings, Trees and Sequences: Computer Science and Computational Biology}, Cambridge University Press, 1997. +% \bibitem{hal35} +% P. Hall. +% On representatives of subsets. +% \emph{Journal London Mathematical Society} 10(1):26--30, 1935. + +\bibitem{hal13} + S. Halim and F. Halim. + \emph{Competitive Programming 3: The New Lower Bound of Programming Contests}, 2013. + +\bibitem{hel62} + M. Held and R. M. Karp. + A dynamic programming approach to sequencing problems. + \emph{Journal of the Society for Industrial and Applied Mathematics}, 10(1):196--210, 1962. + +\bibitem{hie73} + C. Hierholzer and C. Wiener. + Über die Möglichkeit, einen Linienzug ohne Wiederholung und ohne Unterbrechung zu umfahren. + \emph{Mathematische Annalen}, 6(1), 30--32, 1873. + +\bibitem{hoa61a} + C. A. R. Hoare. + Algorithm 64: Quicksort. + \emph{Communications of the ACM}, 4(7):321, 1961. + +\bibitem{hoa61b} + C. A. R. Hoare. + Algorithm 65: Find. + \emph{Communications of the ACM}, 4(7):321--322, 1961. + +\bibitem{hop71} + J. E. Hopcroft and J. D. Ullman. + A linear list merging algorithm. + Technical report, Cornell University, 1971. + +\bibitem{hor74} + E. Horowitz and S. Sahni. + Computing partitions with applications to the knapsack problem. + \emph{Journal of the ACM}, 21(2):277--292, 1974. + \bibitem{huf52} + D. A. Huffman. A method for the construction of minimum-redundancy codes. \emph{Proceedings of the IRE}, 40(9):1098--1101, 1952. @@ -125,44 +214,140 @@ Efficient randomized pattern-matching algorithms. \emph{IBM Journal of Research and Development}, 31(2):249--260, 1987. -\bibitem{kas61} - P. W. Kasteleyn. - The statistics of dimers on a lattice: I. The number of dimer arrangements on a quadratic lattice. - \emph{Physica}, 27(12):1209--1225, 1961. +\bibitem{kle05} + J. Kleinberg and É. Tardos. + \emph{Algorithm Design}, Pearson, 2005. + +% \bibitem{kas61} +% P. W. Kasteleyn. +% The statistics of dimers on a lattice: I. The number of dimer arrangements on a quadratic lattice. +% \emph{Physica}, 27(12):1209--1225, 1961. + +\bibitem{knu982} + D. E. Knuth. + \emph{The Art of Computer Programming. Volume 2: Seminumerical Algorithms}, Addison–Wesley, 1998 (3rd edition). + +\bibitem{knu983} + D. E. Knuth. + \emph{The Art of Computer Programming. Volume 3: Sorting and Searching}, Addison–Wesley, 1998 (2nd edition). + +% \bibitem{kon31} +% D. Kőnig. +% Gráfok és mátrixok. +% \emph{Matematikai és Fizikai Lapok}, 38(1):116--119, 1931. \bibitem{kru56} J. B. Kruskal. On the shortest spanning subtree of a graph and the traveling salesman problem. \emph{Proceedings of the American Mathematical Society}, 7(1):48--50, 1956. +\bibitem{lev66} + V. I. Levenshtein. + Binary codes capable of correcting deletions, insertions, and reversals. + \emph{Soviet physics doklady}, 10(8):707--710, 1966. + \bibitem{mai84} M. G. Main and R. J. Lorentz. An $O(n \log n)$ algorithm for finding all repetitions in a string. \emph{Journal of Algorithms}, 5(3):422--432, 1984. +% \bibitem{ore60} +% Ø. Ore. +% Note on Hamilton circuits. +% \emph{The American Mathematical Monthly}, 67(1):55, 1960. + \bibitem{pac13} J. Pachocki and J. Radoszweski. Where to use and how not to use polynomial string hashing. - \emph{Olympiads in Informatics}, 2013. + \emph{Olympiads in Informatics}, 7(1):90--100, 2013. + +% \bibitem{pic99} +% G. Pick. +% Geometrisches zur Zahlenlehre. +% \emph{Sitzungsberichte des deutschen naturwissenschaftlich-medicinischen Vereines +% für Böhmen "Lotos" in Prag. (Neue Folge)}, 19:311--319, 1899. + +\bibitem{pea05} + D. Pearson. + A polynomial-time algorithm for the change-making problem. + \emph{Operations Research Letters}, 33(3):231--234, 2005. \bibitem{pri57} R. C. Prim. Shortest connection networks and some generalizations. \emph{Bell System Technical Journal}, 36(6):1389--1401, 1957. +% \bibitem{pru18} +% H. Prüfer. +% Neuer Beweis eines Satzes über Permutationen. +% \emph{Arch. Math. Phys}, 27:742--744, 1918. + +\bibitem{q27} + 27-Queens Puzzle: Massively Parallel Enumeration and Solution Counting. + \url{https://github.com/preusser/q27} + +\bibitem{sha75} + M. I. Shamos and D. Hoey. + Closest-point problems. + \emph{16th Annual Symposium on Foundations of Computer Science}, 151--162, 1975. + \bibitem{sha81} M. Sharir. A strong-connectivity algorithm and its applications in data flow analysis. \emph{Computers \& Mathematics with Applications}, 7(1):67--72, 1981. +\bibitem{ski08} + S. S. Skiena. + \emph{The Algorithm Design Manual}, Springer, 2008 (2nd edition). + +\bibitem{ski03} + S. S. Skiena and M. A. Revilla. + \emph{Programming Challenges: The Programming Contest Training Manual}, + Springer, 2003. + +\bibitem{spr35} + R. Sprague. + Über mathematische Kampfspiele. + \emph{Tohoku Mathematical Journal}, 41:438--444, 1935. + +\bibitem{sta06} + P. Stańczyk. + \emph{Algorytmika praktyczna w konkursach Informatycznych}, + MSc thesis, University of Warsaw, 2006. + \bibitem{str69} V. Strassen. Gaussian elimination is not optimal. \emph{Numerische Mathematik}, 13(4):354--356, 1969. -\bibitem{tem61} - H. N. V. Temperley and M. E. Fisher. - Dimer problem in statistical mechanics -- an exact result. - \emph{Philosophical Magazine}, 6(68):1061--1063, 1961. +\bibitem{tar75} + R. E. Tarjan. + Efficiency of a good but not linear set union algorithm. + \emph{Journal of the ACM}, 22(2):215--225, 1975. + +\bibitem{tar84} + R. E. Tarjan and U. Vishkin. + Finding biconnected componemts and computing tree functions in logarithmic parallel time. + \emph{25th Annual Symposium on Foundations of Computer Science}, 12--20, 1984. + +% \bibitem{tem61} +% H. N. V. Temperley and M. E. Fisher. +% Dimer problem in statistical mechanics -- an exact result. +% \emph{Philosophical Magazine}, 6(68):1061--1063, 1961. + +\bibitem{war23} + H. C. von Warnsdorf. + \emph{Des Rösselsprunges einfachste und allgemeinste Lösung}. + Schmalkalden, 1823. + +\bibitem{war62} + S. Warshall. + A theorem on boolean matrices. + \emph{Journal of the ACM}, 9(1):11--12, 1962. + +% \bibitem{zec72} +% E. Zeckendorf. +% Représentation des nombres naturels par une somme de nombres de Fibonacci ou de nombres de Lucas. +% \emph{Bull. Soc. Roy. Sci. Liege}, 41:179--182, 1972. \end{thebibliography} \ No newline at end of file diff --git a/preface.tex b/preface.tex index 32806cc..b5c8169 100644 --- a/preface.tex +++ b/preface.tex @@ -12,7 +12,7 @@ The book is especially intended for students who want to learn algorithms and possibly participate in the International Olympiad in Informatics (IOI) or -the International Collegiate Programming Contest (ICPC). +in the International Collegiate Programming Contest (ICPC). Of course, the book is also suitable for anybody else interested in competitive programming.