├── 00_warmup
└── README.md
├── 01_introduction
├── README.md
├── aflv_01_introduction.pdf
├── aflv_01_introduction.tex
└── kattis.png
├── 02_data_structures
├── README.md
├── aflv_02_data_structures.pdf
├── aflv_02_data_structures.tex
├── backspace.cpp
├── grandpabernie.cpp
├── kattis.png
└── simpleaddition.cpp
├── 03_data_structures
├── README.md
├── aflv_03_data_structures.pdf
├── aflv_03_data_structures.tex
├── kattis.png
├── segment_tree.cpp
├── supercomputer.cpp
├── supercomputer_2.cpp
├── union_find.cpp
└── wheresmyinternet.cpp
├── 04_problem_solving_paradigms
├── README.md
├── aflv_04_problem_solving_paradigms.pdf
├── aflv_04_problem_solving_paradigms.tex
├── batmanacci.cpp
├── bsearch2.cpp
├── closestsums.cpp
├── kattis.png
├── luckynumber.cpp
└── pie2.cpp
├── 05_greedy_algorithms
└── README.md
├── 05a_problem_session_1
└── README.md
├── 06_dynamic_programming
├── README.md
├── aflv_06_dynamic_programming.pdf
├── aflv_06_dynamic_programming.tex
├── coin_change2.cpp
├── coin_change_expl.cpp
├── fibonacci2.cpp
├── kattis.png
├── lcs_2.cpp
└── lis_2.cpp
├── 07_graphs_1
├── README.md
├── aflv_07_graphs_1.pdf
├── aflv_07_graphs_1.tex
├── bfs.cpp
├── bridges_2.cpp
├── kattis.png
└── tourist.cpp
├── 08_graphs_2
├── README.md
├── aflv_08_graphs_2.pdf
├── aflv_08_graphs_2.tex
└── kattis.png
├── 09_mathematics
├── README.md
├── aflv_10_mathematics.pdf
├── aflv_10_mathematics.tex
└── kattis.png
├── 09a_problem_session_2
└── README.md
├── 10_graphs_3_network_flow
├── README.md
├── bipartite_matching_2.cpp
├── flow_network.cpp
├── internet.cpp
└── tshirts_3.cpp
├── 11_strings
├── README.md
├── aflv_11_strings.pdf
├── aflv_11_strings.tex
├── kattis.png
├── kmp.cpp
├── longest_common_substring_3.cpp
└── suffix_array_2.cpp
├── 12_geometry
├── README.md
├── aflv_12_geometry.pdf
├── aflv_12_geometry.tex
├── geometry.cpp
└── kattis.png
├── 12a_final_exam
└── README.md
├── LICENSE
└── README.md
/00_warmup/README.md:
--------------------------------------------------------------------------------
1 | # Warmup problems
2 |
3 | We posted this optional set of problems as a warmup for those who were eager to get started.
4 |
Problems
5 |
15 |
--------------------------------------------------------------------------------
/01_introduction/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 1: Introduction
2 | Covers some basic things about the course, and then introduces competitive programming.
3 |
4 | Problems
5 | Solve some of the following problems on Kattis. You need 5 points to get full score.
6 |
13 | Bonus problems
14 | If you want a challenge, you can try solving the following bonus problems.
15 |
19 |
--------------------------------------------------------------------------------
/01_introduction/aflv_01_introduction.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/01_introduction/aflv_01_introduction.pdf
--------------------------------------------------------------------------------
/01_introduction/aflv_01_introduction.tex:
--------------------------------------------------------------------------------
1 | \documentclass[10pt]{beamer}
2 | \usepackage[utf8]{inputenc}
3 | \usepackage[T1]{fontenc}
4 | \usetheme{metropolis}
5 | \usepackage{booktabs}
6 | \usepackage[scale=2]{ccicons}
7 | \usepackage{pgfplots}
8 | \usepgfplotslibrary{dateplot}
9 | \usepackage{xspace}
10 | \usepackage{pbox}
11 |
12 | % a few macros
13 | \newcommand{\bi}{\begin{itemize}}
14 | \newcommand{\ei}{\end{itemize}}
15 | \newcommand{\ig}{\includegraphics}
16 |
17 | % title info
18 | \title{Introduction}
19 | \author{Bjarki Ágúst Guðmundsson\\ Tómas Ken Magnússon}
20 | \institute{\href{http://ru.is/td}{School of Computer Science} \\[2pt] \href{http://ru.is}{Reykjavík University}}
21 | \titlegraphic{\hfill\includegraphics[height=0.6cm]{kattis}}
22 | \date{\textbf{Árangursrík forritun og lausn verkefna}}
23 |
24 | % Tikz
25 | \usepackage{tikz}
26 | \usetikzlibrary{arrows,shapes}
27 |
28 | % Minted
29 | \usepackage{minted}
30 | \usemintedstyle{manni}
31 | \newminted{cpp}{fontsize=\footnotesize}
32 |
33 | % Graph styles
34 | \tikzstyle{vertex}=[circle,fill=black!50,minimum size=15pt,inner sep=0pt, font=\small]
35 | \tikzstyle{selected vertex} = [vertex, fill=red!24]
36 | \tikzstyle{edge} = [draw,thick,-]
37 | \tikzstyle{dedge} = [draw,thick,->]
38 | \tikzstyle{weight} = [font=\scriptsize,pos=0.5]
39 | \tikzstyle{selected edge} = [draw,line width=2pt,-,red!50]
40 | \tikzstyle{ignored edge} = [draw,line width=5pt,-,black!20]
41 |
42 |
43 | \begin{document}
44 | \maketitle
45 |
46 | \begin{frame}{Welcome}
47 | \bi
48 | \item T-414-AFLV, Árangursrík forritun og lausn verkefna
49 |
50 | \vspace{10pt}
51 |
52 | \item Bjarki Ágúst Guðmundsson, {\alert{bjarkig12@ru.is}}
53 | \item Tómas Ken Magnússon, {\alert{tomasm12@ru.is}}
54 | \ei
55 | \end{frame}
56 |
57 | \begin{frame}{Goal}
58 | \bi
59 | \item Given a problem, we want to
60 | \bi
61 | \item solve it efficiently
62 | \item by using algorithms and data structures,
63 | \item convert our solution into a program,
64 | \item do it as quickly as possible (under pressure)
65 | \item and do it correctly (without bugs)
66 | \ei
67 |
68 | \vspace{20pt}
69 |
70 | \item This course will exercise this process
71 | \ei
72 | \end{frame}
73 |
74 | \begin{frame}{How?}
75 | \bi
76 | \item Study common types of problems
77 | \item Show common applications of algorithms and data structures you already know from
78 | \bi
79 | \item Reiknirit (the algorithms course)
80 | \item Gagnaskipan (the data structures course)
81 | \ei
82 | \item Introduce other common algorithms and data structures
83 | \item Go over some commonly used theory
84 | \item Practice problem solving
85 | \item Practice programming
86 | \item More practice
87 | \item More practice
88 | \ei
89 | \end{frame}
90 |
91 | \begin{frame}{Course book}
92 | \bi
93 | \item \alert{Competitive Programming} by Steven Halim
94 | \item First edition can be downloaded from the book homepage:
95 | \item \textbf{https://sites.google.com/site/stevenhalim/}
96 | \vspace{10pt}
97 | \item We will loosely follow the first edition
98 | \item There's also a 2nd and 3rd edition (both should be compatible with our course), but they need to be ordered online
99 | \ei
100 | \end{frame}
101 |
102 | \begin{frame}{Piazza}
103 | \bi
104 | \item Piazza can be used to ask questions
105 | \item \textbf{https://piazza.com/class/in9iwmhczfd1dv}
106 | \ei
107 | \end{frame}
108 |
109 | \begin{frame}{Course schedule}
110 | \scriptsize
111 | \begin{center}
112 | \begin{tabular}{cl|ll}
113 | Class no. & Date & Topics & Activities \\
114 | \hline
115 | 1 & 25.04 & Introduction & \\
116 | 2 & 26.04 & Data structures and libraries & \\
117 | 3 & 27.04 & Data structures & \\
118 | 4 & 28.04 & Problem solving paradigms & \\
119 | 5 & 29.04 & Greedy algorithms & Problem session I \\
120 | \hline
121 | & 30.04 & & \\
122 | & 01.05 & & Problem sets week 1 \\
123 | \hline
124 | 6 & 02.05 & Dynamic programming & \\
125 | 7 & 03.05 & Unweighted graphs & \\
126 | 8 & 04.05 & Graphs & \\
127 | 9 & 05.05 & Network flow & \\
128 | 10 & 06.05 & & Problem session II \\
129 | \hline
130 | & 07.05 & & \\
131 | & 08.05 & & Problem sets week 2 \\
132 | \hline
133 | 11 & 09.05 & Mathematics & \\
134 | 12 & 10.05 & Strings & \\
135 | 13 & 11.05 & Geometry & \\
136 | 14 & 12.05 & & \\
137 | 15 & 13.05 & & Final exam \\
138 | \hline
139 | & 14.05 & & \\
140 | & 15.05 & & Problem sets week 3, Bonus problems \\
141 | \hline
142 | \end{tabular}
143 | \end{center}
144 | \end{frame}
145 |
146 | \begin{frame}{Problem sets}
147 | \bi
148 | \item Each class covers a topic
149 | \item A talk about the topic before noon
150 | \item After noon you get a set of problems about that topic
151 | % \item You should solve them individually
152 | % \item You can solve the problems in groups of up to three people, but each individual must hand in their own code
153 | \item Groups of up to three people can discuss the problems, but each individual must write and hand in their own code
154 | \bi
155 | \item We will check for similar submissions, and take action if we think that people are cheating
156 | \ei
157 | \ei
158 | \end{frame}
159 |
160 | \begin{frame}{Problem sets}
161 | \bi
162 | \item Each problem set has 5 problems
163 | \item Each problem is assigned some amount of points
164 | \item To get a perfect score you need to get at least a certain amount of points
165 | \item The grade follows linearly from the number of points you get
166 | \bi
167 | \item If you get 85\%{} of the required points, your grade is 8.5
168 | \item If you get 50\%{} of the required points, your grade is 5.0
169 | \item If you get 100\%{} or more of the required points, your grade is 10.0
170 | \ei
171 |
172 | \vspace{10pt}
173 | \item The deadline for a problem set is the following Sunday
174 | \item Except for Friday's problem set, which is handed in the Sunday next week
175 | \ei
176 | \end{frame}
177 |
178 | \begin{frame}{Bonus problems}
179 | \bi
180 | \item Each problem set contains two challenging bonus problems
181 | \item Deadline for all bonus problems is the same as the deadline for the last problem set
182 | \item Bonus problems are only taken into account if the student would pass the course before they're taken into account
183 | \ei
184 | \end{frame}
185 |
186 | \begin{frame}{Late handins, partial grading}
187 | \bi
188 | \item Late handins will not be accepted
189 | \bi
190 | \item There should be more than enough time for each problem set
191 | \ei
192 | \item Solutions will not be partially graded %, either they're correct or they aren't
193 | \ei
194 | \end{frame}
195 |
196 | \begin{frame}{Problem sessions}
197 | \bi
198 | \item On each Friday is a programming contest
199 | \item Problems will be related to topics covered so far
200 | \item Teams of up to three people compete together
201 | \item Each team can only use a single computer
202 | \ei
203 | \end{frame}
204 |
205 | \begin{frame}{Final exam}
206 | \bi
207 | \item Will be held on the last Friday
208 | \item Similar to a problem set from all the topics
209 | \vspace{10pt}
210 | \item Need to pass the exam to pass the course
211 | \ei
212 | \end{frame}
213 |
214 | \begin{frame}{Course evaluation}
215 | \begin{center}
216 | \begin{tabular}{lr}
217 | Problem sets & $70\%$ \\
218 | Problem sessions & $10\%$ \\
219 | Final exam & $20\%$ \\
220 | Bonus problems & $20\%$ \\
221 | \hline
222 | Total & $120\%$ \\
223 | \end{tabular}
224 | \end{center}
225 |
226 | \bi
227 | \item Remember that bonus problems are only considered if the student
228 | passes the course, and is only used to raise the final grade
229 | \item A final grade greater than 10 will be reduced down to 10
230 | \ei
231 | \end{frame}
232 |
233 |
234 | \section{Introduction}
235 | \begin{frame}{The problems}
236 | \bi
237 | \item Typical programming contest problems
238 | \item Usually consists of
239 | \bi
240 | \item Problem description
241 | \item Input description
242 | \item Output description
243 | \item Example input/output
244 | \item A time limit in seconds
245 | \item A memory limit in bytes
246 | \ei
247 | \item You are asked to write a program that solves the problem for all valid inputs
248 | \item The program must not exceed time or memory limits
249 | \ei
250 | \end{frame}
251 |
252 | \begin{frame}{Example problem}
253 | \begin{block}{Problem description}
254 | Write a program that multiplies pairs of integers.
255 | \end{block}
256 |
257 | \vspace{10pt}
258 |
259 | \begin{block}{Input description}
260 | Input starts with one line containing an integer $T$, where $1\leq T \leq
261 | 100$, denoting the number of test cases. Then $T$ lines follow, each
262 | containing a test case. Each test case consists of two integers $A,B$,
263 | where $-2^{20} \leq A,B \leq 2^{20}$, separated by a single space.
264 | \end{block}
265 |
266 | \vspace{10pt}
267 |
268 | \begin{block}{Output description}
269 | For each test case, output one line containing the value of $A\times B$.
270 | \end{block}
271 | \end{frame}
272 |
273 | \begin{frame}{Example problem}
274 | \begin{center}
275 | \begin{tabular}{|l|l|}
276 | \hline
277 | {\footnotesize Sample input} & {\footnotesize Sample output} \\
278 | \hline
279 | \begin{minipage}{80pt}
280 | \vspace{10pt}
281 | \ttfamily
282 | 4\\
283 | 3 4\\
284 | 13 0\\
285 | 1 8\\
286 | 100 100\\
287 | \end{minipage}
288 | &
289 | \begin{minipage}{80pt}
290 | \vspace{10pt}
291 | \ttfamily
292 | 12\\
293 | 0\\
294 | 8\\
295 | 10000\\
296 | \end{minipage}
297 | \\
298 | \hline
299 | \end{tabular}
300 | \end{center}
301 |
302 | \end{frame}
303 |
304 | \begin{frame}[fragile]{Example solution}
305 | \begin{minted}[fontsize=\scriptsize]{cpp}
306 | #include
307 | using namespace std;
308 |
309 | int main() {
310 | int T;
311 | cin >> T;
312 |
313 | for (int t = 0; t < T; t++) {
314 |
315 | int A, B;
316 | cin >> A >> B;
317 |
318 | cout << A * B << endl;
319 | }
320 |
321 | return 0;
322 | }
323 | \end{minted}
324 |
325 | \bi
326 | \onslide<2->{\item Is this solution correct? \onslide<5->{\alert{No!}}}
327 | \onslide<3->{\item What if $A = B = 2^{20}$? \onslide<4->{The output is $0$...}}
328 | \ei
329 | \end{frame}
330 |
331 | \begin{frame}[fragile]{Example solution}
332 | \bi
333 | \item When $A = B = 2^{20}$, the answer should be $2^{40}$
334 | \onslide<2->{\item Too big to fit in a 32-bit integer, so it overflows}
335 | \onslide<3->{\item Using 64-bit integers should be enough}
336 | \ei
337 | \end{frame}
338 |
339 | \begin{frame}[fragile]{Example solution}
340 | \begin{minted}[fontsize=\scriptsize]{cpp}
341 | #include
342 | using namespace std;
343 |
344 | int main() {
345 | int T;
346 | cin >> T;
347 |
348 | for (int t = 0; t < T; t++) {
349 |
350 | long long A, B;
351 | cin >> A >> B;
352 |
353 | cout << A * B << endl;
354 | }
355 |
356 | return 0;
357 | }
358 | \end{minted}
359 |
360 | \bi
361 | \onslide<2->{\item Is this solution correct? \onslide<3->{{\alert{Yes!}}}}
362 | \ei
363 | \end{frame}
364 |
365 |
366 | \begin{frame}{Automatic judging}
367 | \bi
368 | \item The problems will be available on \alert{Kattis}:
369 | \item \textbf{https://ru.kattis.com/}
370 | \vspace{20pt}
371 | \item Kattis is an online judge, similar to Mooshak
372 | \item You will submit your solutions to Kattis, and get immediate feedback about the solution
373 | \item You can submit in any of the supported languages:
374 | \bi
375 | \item C
376 | \item C++
377 | \item Java
378 | \item Python 2
379 | \item Python 3
380 | \item C\#{}
381 | \item and others
382 | \ei
383 | \ei
384 | \end{frame}
385 |
386 | \begin{frame}{Judge verdicts}
387 | \bi
388 | \item Feedback about solutions is limited
389 | \item You will (usually) receive one of:
390 | \bi
391 | \item Accepted
392 | \item Wrong Answer
393 | \item Compile Error
394 | \item Run Time Error
395 | \item Time Limit Exceeded
396 | \item Memory Limit Exceeded
397 | \ei
398 |
399 | \item We will not reveal which test cases Kattis uses to test your solution
400 | \ei
401 | \end{frame}
402 |
403 | \begin{frame}{Tips}
404 | \bi
405 | \item There are a couple of tips and guidelines you can keep in mind towards becoming a more effective programmer and better problem solver
406 |
407 | \ei
408 | \end{frame}
409 |
410 | \begin{frame}{Tip 0: Faster typing}
411 | \bi
412 | \item Become a faster/better typist
413 | \item Don't let your fingers be the limiting factor of solving problems quickly
414 | \item Good problem solvers have simple solutions; they don't have to type as much, but it's still important to type in quickly
415 | \vspace{20pt}
416 | \item TypeRacer is a fun and effective way to practice:
417 | \item \textbf{http://play.typeracer.com/}
418 | \ei
419 | \end{frame}
420 |
421 | \begin{frame}{Tip 1: Quickly classify problems}
422 | \bi
423 | \item Practice quickly identifying problem types
424 | \vspace{10pt}
425 | \item Rate of appearance of different problem types in recent ICPC Asia Regional problem sets (which usually consists of 7-11 problems):
426 | \ei
427 |
428 | \vspace{5pt}
429 |
430 | {
431 | \scriptsize
432 | \begin{center}
433 | \begin{tabular}{ccc}
434 | Category & Sub-Category & Frequency \\
435 | \hline
436 | Ad Hoc & Straightforward & 1-2 \\
437 | Ad Hoc & Simulation & 0-1 \\
438 | Complete Search & Iterative & 0-1 \\
439 | Complete Search & Backtracking & 0-1 \\
440 | Divide \&{} Conquer & & 0-1 \\
441 | Greedy & Classic & 0 \\
442 | Greedy & Original & 1 \\
443 | Dynamic Programming & Classic & 0 \\
444 | Dynamic Programming & Original & 1-3 \\
445 | Graph & & 1-2 \\
446 | Mathematics & & 1-2 \\
447 | String Processing & & 1 \\
448 | Computational Geometry & & 1 \\
449 | Harder Problems & & 0-1 \\
450 | \end{tabular}
451 | \end{center}
452 | }
453 | \end{frame}
454 |
455 | \begin{frame}{Tip 2: Do Algorithm Analysis}
456 | \bi
457 | \item When solving a problem, our solution has to be fast enough and can not use too much memory
458 | \item We also want our solution to be as simple as possible
459 | \vspace{5pt}
460 | \item We can use Algorithm Analysis to determine if a solution will run within the time limit
461 | \item Rule of thumb: $10^{8}$ operations per second
462 | \vspace{10pt}
463 | \item<2-> We want to sort $n \leq 10^{6}$ integers, and we have 3 seconds.
464 | \bi
465 | \item Can we use a simple $O(n^2)$ bubble sort?
466 | \item What about a more complex $O(n\log n)$ merge sort?
467 | \ei
468 | \vspace{5pt}
469 | \item<3-> We want to sort $n \leq 10^{3}$ integers, and we have 3 seconds.
470 | \bi
471 | \item Can we now use the simple $O(n^2)$ bubble sort?
472 | \ei
473 | \vspace{5pt}
474 | \item<4-> Always go for the simplest solution that will pass the time limit
475 | \ei
476 | \end{frame}
477 |
478 | \begin{frame}{Tip 2: Do Algorithm Analysis}
479 | \bi
480 | \item You should practice doing approximate mental calculations
481 | \item Rule of thumb: $2^{10} \approx 10^{3}$
482 | \vspace{10pt}
483 | \item Sometimes you have a solution that you're not sure is correct
484 | \item Try to prove it's correct!
485 | \item Even if you don't manage to prove or disprove it, you will probably get a better understanding of the problem
486 | \vspace{20pt}
487 | \ei
488 | \end{frame}
489 |
490 | \begin{frame}{Tip 2: Do Algorithm Analysis}
491 | \vspace{10pt}
492 | {
493 | \scriptsize
494 | \begin{center}
495 | \begin{tabular}{c|c|c}
496 | $n$ & Slowest Accepted Algorithm & Example \\
497 | \hline
498 | $\leq 10$ & $O(n!), O(n^6)$ & Enumerating a permutation \\
499 | $\leq 15$ & $O(2^n\times n^2)$ & DP TSP \\
500 | $\leq 20$ & $O(2^n), O(n^5)$ & DP + bitmask technique \\
501 | $\leq 50$ & $O(n^4)$ & DP with 3 dimensions + $O(n)$ loop, choosing $_nC_4$ \\
502 | $\leq 10^2$ & $O(n^3)$ & Floyd Warshall's \\
503 | $\leq 10^3$ & $O(n^2)$ & Bubble/Selection/Insertion sort \\
504 | $\leq 10^5$ & $O(n\log_2{n})$ & Merge sort, building a Segment tree \\
505 | $\leq 10^6$ & $O(n), O(\log_2{n}), O(1)$ & Usually, contest problems have $n\leq10^6$ (to read input) \\
506 | \end{tabular}
507 | \end{center}
508 | }
509 | \end{frame}
510 |
511 | \begin{frame}{Tip 3: Master Programming Languages}
512 | \bi
513 | \item You should know your programming language like the back of your hand
514 | \item This includes your programming language's library
515 | \bi
516 | \item C++'s Standard Template Library
517 | \item The Java Class Library
518 | \ei
519 | \item If it's already implemented in the standard library, you usually don't need to implement it yourself
520 | \ei
521 | \end{frame}
522 |
523 | \begin{frame}{Tip 4: Test your solution}
524 | \bi
525 | \item You want to make sure your solution is correct and runs within the time limit
526 | \item Or you already know it's wrong, but don't know why
527 | \vspace{10pt}
528 | \item Try to break your solution by finding a counterexample (an input for which your solution gives incorrect output, or takes too long to compute an answer)
529 | \item Try edge cases, large inputs, ...
530 | \ei
531 | \end{frame}
532 |
533 | \begin{frame}{Tip 5: Practice and more practice}
534 | \bi
535 | \item Problem solving and programming skills come with practice
536 | \item Lots of online judges that let you solve problems from past contests
537 | \item Some of these online judges also hold contests frequently
538 | \item Open Kattis, Codeforces, HackerRank, Codechef, UVa, TopCoder, ...
539 | \ei
540 | \end{frame}
541 |
542 |
543 | \section{Ad Hoc Problems}
544 |
545 | \begin{frame}{Ad Hoc problems}
546 | \bi
547 | \item The simplest kind of problem
548 | \item Just do what the problem description tells you
549 | \item Straightforward or a simulation
550 | \item Time limit is not an issue
551 | \item Sometimes long and misleading problem descriptions
552 | \item Sometimes tricky edge cases
553 | \item Complex problems can be hard to implement
554 | \ei
555 | \end{frame}
556 |
557 | \begin{frame}{Problem: Cost Cutting}
558 | \vspace{10pt}
559 | {
560 | \small
561 | Company XYZ have been badly hit by recession and is taking a lot of cost cutting measures. Some of these measures include giving up office space, going open source, reducing incentives, cutting on luxuries and issuing pink slips.
562 |
563 | \vspace{10pt}
564 |
565 | They have got three (3) employees working in the accounts department and are going to lay-off two (2) of them. After a series of meetings, they have decided to dislodge the person who gets the most salary and the one who gets the least. This is usually the general trend during crisis like this.
566 | You will be given the salaries of these 3 employees working in the accounts department. You have to find out the salary of the person who survives.
567 | }
568 | \end{frame}
569 |
570 | \begin{frame}{Problem: Cost Cutting}
571 | \begin{block}{Input}
572 | {\small
573 | The first line of input is an integer $T$ ($T<20$) that indicates the number of test cases. Each case consists of a line with 3 distinct positive integers. These 3 integers represent the salaries of the three employees. All these integers will be in the range $[1000, 10000]$.
574 | }
575 | \end{block}
576 |
577 | \vspace{20pt}
578 | \begin{block}{Output}
579 | {\small
580 | For each case, output the case number followed by the salary of the person who survives.
581 | }
582 | \end{block}
583 | \end{frame}
584 |
585 | \begin{frame}{Problem: Cost Cutting}
586 | \begin{center}
587 | \begin{tabular}{|l|l|}
588 | \hline
589 | {\footnotesize Sample input} & {\footnotesize Sample output} \\
590 | \hline
591 | \begin{minipage}{100pt}
592 | \vspace{10pt}
593 | \ttfamily
594 | 3\\
595 | 1000 2000 3000\\
596 | 3000 2500 1500\\
597 | 1500 1200 1800\\
598 | \end{minipage}
599 | &
600 | \begin{minipage}{100pt}
601 | \vspace{10pt}
602 | \ttfamily
603 | Case 1: 2000\\
604 | Case 2: 2500\\
605 | Case 3: 1500\\
606 | \end{minipage}
607 | \\
608 | \hline
609 | \end{tabular}
610 | \end{center}
611 | \end{frame}
612 |
613 |
614 | \begin{frame}[fragile]{Cost Cutting: Solution}
615 | \begin{minted}[fontsize=\scriptsize]{cpp}
616 | #include
617 | #include
618 | using namespace std;
619 |
620 | int main() {
621 | int T;
622 | scanf("%d", &T);
623 |
624 | for (int t = 0; t < T; t++) {
625 |
626 | int salary[3];
627 | scanf("%d", &salary[0]);
628 | scanf("%d", &salary[1]);
629 | scanf("%d", &salary[2]);
630 |
631 | sort(salary, salary + 3);
632 |
633 | printf("Case %d: %d\n", t + 1, salary[1]);
634 | }
635 |
636 | return 0;
637 | }
638 | \end{minted}
639 | \end{frame}
640 |
641 | \begin{frame}{Problem: SMS Typing}
642 |
643 | {\small
644 | Cell phones have become an essential part of modern life. In addition to
645 | making voice calls, cell phones can be used to send text messages, which
646 | are known as SMS for short. Unlike computer keyboards, most cell phones
647 | have limited number of keys. To accommodate all alphabets, letters are
648 | compacted into single key. Therefore, to type certain characters, a key
649 | must be repeatedly pressed until that character is shown on the display
650 | panel.\\
651 | \vspace{10pt}
652 | In this problem we are interested in finding out the number of times keys on a cell phone must be
653 | pressed to type a particular message.
654 | }
655 | \end{frame}
656 |
657 |
658 | \begin{frame}{Problem: SMS Typing}
659 |
660 | {
661 | \small
662 | In this problem we will assume that the key pad of our cell phone is arranged as follows.
663 |
664 | \begin{center}
665 | \begin{tabular}{|c|c|c|}
666 | \hline
667 | & abc & def \\
668 | \hline
669 | ghi & jkl & mno \\
670 | \hline
671 | pqrs & tuv & wxyz \\
672 | \hline
673 | & & \\
674 | \hline
675 | \end{tabular}
676 | \end{center}
677 |
678 | In the above grid each cell represents one key. Here means a space. In order to type the letter
679 | ‘a’, we must press that key once, however to type ‘b’ the same key must be repeatedly pressed twice
680 | and for ‘c’ three times. In the same manner, one key press for ‘d’, two for ‘e’ and three for ‘f’. This is
681 | also applicable for the remaining keys and letters. Note that it takes a single press to type a space.
682 | }
683 |
684 | \end{frame}
685 |
686 | \begin{frame}{Problem: SMS Typing}
687 | \begin{block}{Input}
688 | {\small
689 | The first line of input will be a positive integer $T$ where $T$ denotes the number of test cases. $T$ lines
690 | will then follow each containing only spaces and lower case letters. Each line will contain at least 1 and
691 | at most 100 characters.
692 | }
693 | \end{block}
694 |
695 | \vspace{20pt}
696 | \begin{block}{Output}
697 | {\small
698 | For every case of input there will be one line of output. It will first contain the case number followed
699 | by the number of key presses required to type the message of that case. Look at the sample output for
700 | exact formatting.
701 | }
702 | \end{block}
703 | \end{frame}
704 |
705 | \begin{frame}{Problem: SMS Typing}
706 | \begin{center}
707 | \begin{tabular}{|l|l|}
708 | \hline
709 | {\footnotesize Sample input} & {\footnotesize Sample output} \\
710 | \hline
711 | \begin{minipage}{150pt}
712 | \vspace{10pt}
713 | \ttfamily
714 | 2\\
715 | welcome to ulab\\
716 | good luck and have fun\\
717 | \end{minipage}
718 | &
719 | \begin{minipage}{100pt}
720 | \vspace{10pt}
721 | \ttfamily
722 | Case \#{}1: 29\\
723 | Case \#{}2: 41\\
724 | \end{minipage}
725 | \\
726 | \hline
727 | \end{tabular}
728 | \end{center}
729 | \end{frame}
730 |
731 | \begin{frame}[fragile]{SMS Typing: Solution}
732 | \begin{minted}[fontsize=\scriptsize]{cpp}
733 | #include
734 | #include
735 | #include
736 | using namespace std;
737 |
738 | string keys[12] = {
739 | "", "abc", "def",
740 | "ghi", "jkl", "mno",
741 | "pqrs", "tuv", "wxyz",
742 | "", " ", ""
743 | };
744 |
745 | int main() {
746 | int T;
747 | scanf("%d\n", &T);
748 |
749 | for (int t = 0; t < T; t++) {
750 |
751 | // Each test case is handled here
752 | }
753 |
754 | return 0;
755 | }
756 | \end{minted}
757 | \end{frame}
758 |
759 | \begin{frame}[fragile]{SMS Typing: Solution}
760 | \begin{minted}[fontsize=\scriptsize]{cpp}
761 |
762 | // Each test case:
763 |
764 | string line;
765 | getline(cin, line);
766 |
767 | int cnt = 0;
768 | for (int i = 0; i < line.size(); i++) {
769 | int cur;
770 | for (int j = 0; j < 12; j++) {
771 | for (int k = 0; k < keys[j].size(); k++) {
772 | if (line[i] == keys[j][k]) {
773 | cur = k + 1;
774 | }
775 | }
776 | }
777 |
778 | cnt += cur;
779 | }
780 |
781 | printf("Case #%d: %d\n", t + 1, cnt);
782 | \end{minted}
783 | \end{frame}
784 |
785 | \begin{frame}{Problem set 1}
786 | \bi
787 | \item The first problem set is already online
788 | \item Deadline is next Sunday
789 | \item We urge you to start right away nonetheless
790 | \ei
791 | \end{frame}
792 |
793 | \end{document}
794 |
--------------------------------------------------------------------------------
/01_introduction/kattis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/01_introduction/kattis.png
--------------------------------------------------------------------------------
/02_data_structures/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 2: Data structures and libraries
2 |
3 | Reviews the most basic data types and data structures. Covers how to represent big integers, sets and graphs, and how to augment binary search trees.
4 |
5 | Problems
6 | Solve some of the following problems on Kattis. You need 3 points to get full score.
7 |
14 | Bonus problems
15 | If you want a challenge, you can try solving the following bonus problems.
16 |
20 |
--------------------------------------------------------------------------------
/02_data_structures/aflv_02_data_structures.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/02_data_structures/aflv_02_data_structures.pdf
--------------------------------------------------------------------------------
/02_data_structures/backspace.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | int main() {
13 | string s;
14 | cin >> s;
15 | deque S;
16 | for (int i = 0; i < s.size(); i++) {
17 | char c = s[i];
18 | if (c == '<') {
19 | S.pop_back();
20 | } else {
21 | S.push_back(c);
22 | }
23 | }
24 |
25 | while (!S.empty()) {
26 | cout << S.front();
27 | S.pop_front();
28 | }
29 | cout << endl;
30 |
31 | return 0;
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/02_data_structures/grandpabernie.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | int main() {
13 | int n;
14 | cin >> n;
15 | map > trips;
16 | for (int i = 0; i < n; i++) {
17 | string name;
18 | int year;
19 | cin >> name >> year;
20 | trips[name].push_back(year);
21 | }
22 | for (map >::iterator it = trips.begin(); it != trips.end(); ++it) {
23 | sort(it->second.begin(), it->second.end());
24 | }
25 | int m;
26 | cin >> m;
27 | for (int i = 0; i < m; i++) {
28 | string name;
29 | int k;
30 | cin >> name >> k;
31 | cout << trips[name][k-1] << endl;
32 | }
33 | return 0;
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/02_data_structures/kattis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/02_data_structures/kattis.png
--------------------------------------------------------------------------------
/02_data_structures/simpleaddition.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | struct big_integer {
13 | string s;
14 | big_integer(string _s) {
15 | s = _s;
16 | }
17 |
18 | big_integer operator + (const big_integer &other) const {
19 | string a = s,
20 | b = other.s;
21 |
22 | reverse(a.begin(), a.end());
23 | reverse(b.begin(), b.end());
24 |
25 | stringstream c;
26 |
27 | int carry = 0;
28 | for (int at = 0; at < size(a) || at < size(b) || carry > 0; at++) {
29 | int cur = carry;
30 | if (at < size(a)) cur += a[at] - '0';
31 | if (at < size(b)) cur += b[at] - '0';
32 |
33 | // if (cur < 10) {
34 | // c << cur;
35 | // carry = 0;
36 | // } else {
37 | // c << (cur - 10);
38 | // carry = 1;
39 | // }
40 |
41 | c << (cur % 10);
42 | carry = cur / 10;
43 | }
44 |
45 | string out = c.str();
46 | reverse(out.begin(), out.end());
47 | return big_integer(out);
48 | }
49 | };
50 |
51 | int main() {
52 | string a, b;
53 | cin >> a >> b;
54 |
55 | big_integer x = a,
56 | y = b;
57 |
58 | big_integer z = x + y;
59 |
60 | cout << z.s << endl;
61 |
62 | return 0;
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/03_data_structures/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 3: Data structures
2 |
3 | Reviews the Union-Find disjoint sets data structure, and covers range queries, Square Root Decomposition and Segment Trees.
4 |
5 | Problems
6 | Solve some of the following problems on Kattis. You need 3 points to get full score.
7 |
14 | Bonus problems
15 | If you want a challenge, you can try solving the following bonus problems.
16 |
20 |
--------------------------------------------------------------------------------
/03_data_structures/aflv_03_data_structures.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/03_data_structures/aflv_03_data_structures.pdf
--------------------------------------------------------------------------------
/03_data_structures/kattis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/03_data_structures/kattis.png
--------------------------------------------------------------------------------
/03_data_structures/segment_tree.cpp:
--------------------------------------------------------------------------------
1 | struct segment_tree {
2 | segment_tree *left, *right;
3 | int from, to, value;
4 | segment_tree(int from, int to)
5 | : from(from), to(to), left(NULL), right(NULL), value(0) { }
6 | };
7 |
8 | segment_tree* build(const vector &arr, int l, int r) {
9 | if (l > r) return NULL;
10 | segment_tree *res = new segment_tree(l, r);
11 | if (l == r) {
12 | res->value = arr[l];
13 | } else {
14 | int m = (l + r) / 2;
15 | res->left = build(arr, l, m);
16 | res->right = build(arr, m + 1, r);
17 | if (res->left != NULL) res->value += res->left->value;
18 | if (res->right != NULL) res->value += res->right->value;
19 | }
20 | return res;
21 | }
22 |
23 | int query(segment_tree *tree, int l, int r) {
24 | if (tree == NULL) return 0;
25 | if (l <= tree->from && tree->to <= r) return tree->value;
26 | if (tree->to < l) return 0;
27 | if (r < tree->from) return 0;
28 | return query(tree->left, l, r) + query(tree->right, l, r);
29 | }
30 |
31 | int update(segment_tree *tree, int i, int val) {
32 | if (tree == NULL) return 0;
33 | if (tree->to < i) return tree->value;
34 | if (i < tree->from) return tree->value;
35 | if (tree->from == tree->to && tree->from == i) {
36 | tree->value = val;
37 | } else {
38 | tree->value = update(tree->left, i, val) + update(tree->right, i, val);
39 | }
40 | return tree->value;
41 | }
42 |
--------------------------------------------------------------------------------
/03_data_structures/supercomputer.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | int main() {
13 | int n, m;
14 | scanf("%d %d\n", &n, &m);
15 |
16 | int k = (int)sqrt(n) + 2;
17 |
18 | vector arr(n);
19 | vector buck((n-1)/k + 1);
20 |
21 | rep(i,0,m) {
22 | char op;
23 | scanf("%c ", &op);
24 | if (op == 'F') {
25 | int x;
26 | scanf("%d\n", &x);
27 | x--;
28 |
29 | if (arr[x] == 0) {
30 | arr[x] = 1;
31 | buck[x/k]++;
32 | } else {
33 | arr[x] = 0;
34 | buck[x/k]--;
35 | }
36 |
37 | } else {
38 | int l, r;
39 | scanf("%d %d\n", &l, &r);
40 | l--, r--;
41 |
42 | int sum = 0;
43 | for (int i = 0; i < buck.size(); i++) {
44 |
45 | int a = k*i,
46 | b = a + k-1;
47 |
48 | if (l <= a && b <= r) {
49 | sum += buck[i];
50 | } else if (b < l || r < a) {
51 | } else {
52 | for (int j = max(l,a); j <= min(b,r); j++) {
53 | sum += arr[j];
54 | }
55 | }
56 | }
57 |
58 | printf("%d\n", sum);
59 | }
60 | }
61 | return 0;
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/03_data_structures/supercomputer_2.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 |
13 | struct segment_tree {
14 | segment_tree *left, *right;
15 | int from, to, value;
16 | segment_tree(int from, int to)
17 | : from(from), to(to), left(NULL), right(NULL), value(0) { }
18 | };
19 | segment_tree* build(const vector &arr, int l, int r) {
20 | if (l > r) return NULL;
21 | segment_tree *res = new segment_tree(l, r);
22 | if (l == r) {
23 | res->value = arr[l];
24 | } else {
25 | int m = (l + r) / 2;
26 | res->left = build(arr, l, m);
27 | res->right = build(arr, m + 1, r);
28 | if (res->left != NULL) res->value += res->left->value;
29 | if (res->right != NULL) res->value += res->right->value;
30 | }
31 | return res;
32 | }
33 | int query(segment_tree *tree, int l, int r) {
34 | if (tree == NULL) return 0;
35 | if (l <= tree->from && tree->to <= r) return tree->value;
36 | if (tree->to < l) return 0;
37 | if (r < tree->from) return 0;
38 | return query(tree->left, l, r) + query(tree->right, l, r);
39 | }
40 | int update(segment_tree *tree, int i) {
41 | if (tree == NULL) return 0;
42 | if (tree->to < i) return tree->value;
43 | if (i < tree->from) return tree->value;
44 | if (tree->from == tree->to && tree->from == i) {
45 | // tree->value = val;
46 | tree->value = 1 - tree->value;
47 | } else {
48 | tree->value = update(tree->left, i) + update(tree->right, i);
49 | }
50 | return tree->value;
51 | }
52 |
53 | int main() {
54 | int n, m;
55 | scanf("%d %d\n", &n, &m);
56 |
57 | vector mem(n,0);
58 | segment_tree *st = build(mem, 0, n-1);
59 |
60 | rep(i,0,m) {
61 | char op;
62 | scanf("%c ", &op);
63 | if (op == 'F') {
64 | int x;
65 | scanf("%d\n", &x);
66 | x--;
67 |
68 | update(st, x);
69 |
70 | } else {
71 | int l, r;
72 | scanf("%d %d\n", &l, &r);
73 | l--, r--;
74 |
75 | printf("%d\n", query(st, l, r));
76 | }
77 | }
78 | return 0;
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/03_data_structures/union_find.cpp:
--------------------------------------------------------------------------------
1 | struct union_find {
2 | vector parent;
3 | union_find(int n) {
4 | parent = vector(n);
5 | for (int i = 0; i < n; i++) {
6 | parent[i] = i;
7 | }
8 | }
9 |
10 | int find(int x) {
11 | if (parent[x] == x) {
12 | return x;
13 | } else {
14 | parent[x] = find(parent[x]);
15 | return parent[x];
16 | }
17 | }
18 |
19 | void unite(int x, int y) {
20 | parent[find(x)] = find(y);
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/03_data_structures/wheresmyinternet.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 |
13 | #define MAXN 200100
14 | int p[MAXN];
15 | int find(int x) {
16 | return p[x] == x ? x : p[x] = find(p[x]); }
17 | void unite(int x, int y) { p[find(x)] = find(y); }
18 |
19 | int main() {
20 | for (int i = 0; i < MAXN; i++) p[i] = i;
21 |
22 | int n, m;
23 | cin >> n >> m;
24 | rep(i,0,m) {
25 | int a, b;
26 | cin >> a >> b;
27 | a--, b--;
28 | unite(a,b);
29 | }
30 |
31 | bool any = false;
32 | rep(i,0,n) {
33 | if (find(i) != find(0)) {
34 | cout << i+1 << endl;
35 | any = true;
36 | }
37 | }
38 |
39 | if (!any) {
40 | cout << "Connected" << endl;
41 | }
42 |
43 | return 0;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 4: Problem solving paradigms
2 |
3 | Introduces problem solving paradigms, and covers complete search, backtracking, and divide & conquer. Covers binary search, and binary exponentiation.
4 |
5 | Problems
6 | Solve some of the following problems on Kattis. You need 3 points to get full score.
7 |
14 | Bonus problems
15 | If you want a challenge, you can try solving the following bonus problems.
16 |
20 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/aflv_04_problem_solving_paradigms.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/04_problem_solving_paradigms/aflv_04_problem_solving_paradigms.pdf
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/aflv_04_problem_solving_paradigms.tex:
--------------------------------------------------------------------------------
1 | \documentclass[10pt]{beamer}
2 | \usepackage[utf8]{inputenc}
3 | \usepackage[T1]{fontenc}
4 | \usetheme{metropolis}
5 | \usepackage{booktabs}
6 | \usepackage[scale=2]{ccicons}
7 | \usepackage{pgfplots}
8 | \usepgfplotslibrary{dateplot}
9 | \usepackage{xspace}
10 | \usepackage{pbox}
11 |
12 | % a few macros
13 | \newcommand{\bi}{\begin{itemize}}
14 | \newcommand{\ei}{\end{itemize}}
15 | \newcommand{\ig}{\includegraphics}
16 | \definecolor{hilight}{RGB}{235,129,27}
17 | \definecolor{vhilight}{RGB}{235,129,27}
18 |
19 | % title info
20 | \title{Problem solving paradigms}
21 | \author{Bjarki Ágúst Guðmundsson\\ Tómas Ken Magnússon}
22 | \institute{\href{http://ru.is/td}{School of Computer Science} \\[2pt] \href{http://ru.is}{Reykjavík University}}
23 | \titlegraphic{\hfill\includegraphics[height=0.6cm]{kattis}}
24 | \date{\textbf{Árangursrík forritun og lausn verkefna}}
25 |
26 | % Tikz
27 | \usepackage{tikz}
28 | \usetikzlibrary{arrows,shapes}
29 |
30 | % Minted
31 | \usepackage{minted}
32 | \usemintedstyle{manni}
33 | \newminted{cpp}{fontsize=\footnotesize}
34 |
35 | % Graph styles
36 | \tikzstyle{vertex}=[circle,fill=black!50,minimum size=15pt,inner sep=0pt, font=\small]
37 | \tikzstyle{selected vertex} = [vertex, fill=red!24]
38 | \tikzstyle{edge} = [draw,thick,-]
39 | \tikzstyle{dedge} = [draw,thick,->]
40 | \tikzstyle{weight} = [font=\scriptsize,pos=0.5]
41 | \tikzstyle{selected edge} = [draw,line width=2pt,-,red!50]
42 | \tikzstyle{ignored edge} = [draw,line width=5pt,-,black!20]
43 |
44 | \tikzset{
45 | treenode/.style = {align=center, inner sep=0pt, text centered,
46 | font=\sffamily},
47 | vertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=black, text width=1.8em},% arbre rouge noir, noeud noir
48 | rvertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=red, text width=1.8em},% arbre rouge noir, noeud noir
49 | }
50 |
51 | \begin{document}
52 | \maketitle
53 |
54 |
55 | \begin{frame}{Today we're going to cover}
56 | \bi
57 | \item Problem solving paradigms
58 | \item Complete search
59 | \item Backtracking
60 | \item Divide and conquer
61 | \ei
62 | \end{frame}
63 |
64 | \begin{frame}{Example problem}
65 | \bi
66 | \item Problem C from NWERC 2006: Pie
67 | \ei
68 | \end{frame}
69 |
70 | \begin{frame}{Problem solving paradigms}
71 | \bi
72 | \item What is a problem solving paradigm?
73 | \item A method to construct a solution to a specific type of problem
74 | % \item One example is "Brute force"
75 | % \bi
76 | % \item the problem asks us to find an object with a specific property (\textit{the problem type})
77 | % \item apply the "Brute force" paradigm: go through all objects, for each of them check if the object has the property, if yes, stop, if no, continue
78 | % \ei
79 | % \vspace{10pt}
80 | \item Today and in later lectures we will study common problem solving paradigms
81 | % \item Each paradigm applies to different kinds of problems
82 | \ei
83 | \end{frame}
84 |
85 | \section{Complete search}
86 | \begin{frame}{Complete search}
87 | \bi
88 | \item We have a finite set of objects
89 | \item We want to find an element in that set which satisfies some constraints
90 | \bi
91 | \item or find \textbf{all} elements in that set which satisfy some constraints
92 | \ei
93 |
94 | \vspace{5pt}
95 | \item Simple! Just go through all elements in the set, and for each of them check if they satisify the constraints
96 | \item Of course it's not going to be very efficient...
97 | \item But remember, we always want the simplest solution that runs in time
98 | \item Complete search should be the first problem solving paradigm you think about when you're trying to solve a problem
99 | \ei
100 | \end{frame}
101 |
102 | % \begin{frame}{Example problem: Vito's family}
103 | % \bi
104 | % \item http://uva.onlinejudge.org/external/100/10041.html
105 | % \ei
106 | % \end{frame}
107 | \begin{frame}{Example problem: Closest Sums}
108 | \bi
109 | \item https://open.kattis.com/problems/closestsums
110 | \ei
111 | \end{frame}
112 |
113 | \begin{frame}{Complete search}
114 | \bi
115 | \item What if the search space is more complex?
116 | \bi
117 | \item All permutations of $n$ items
118 | \item All subsets of $n$ items
119 | \item All ways to put $n$ queens on an $n\times n$ chessboard without any queen attacking any other queen
120 | \ei
121 | \item How are we supposed to iterate through the search space?
122 | \item Let's take a better look at these examples
123 | \ei
124 | \end{frame}
125 |
126 | \begin{frame}[fragile]{Iterating through permutations}
127 | \bi
128 | \item Already implemented in many standard libraries:
129 | \bi
130 | \item \texttt{next\_{}permutation} in C++
131 | \item \texttt{itertools.permutations} in Python
132 | \ei
133 | \ei
134 |
135 | \begin{minted}{cpp}
136 | int n = 5;
137 | vector perm(n);
138 | for (int i = 0; i < n; i++) perm[i] = i + 1;
139 |
140 | do {
141 | for (int i = 0; i < n; i++) {
142 | printf("%d ", perm[i]);
143 | }
144 | printf("\n");
145 |
146 | } while (next_permutation(perm.begin(), perm.end()));
147 | \end{minted}
148 |
149 | \end{frame}
150 |
151 | \begin{frame}{Iterating through permutations}
152 | \bi
153 | \item Even simpler in Python...
154 | \vspace{20pt}
155 | \item Remember that there are $n!$ permutations of length $n$, so usually you can only go through all permutations if $n \leq 11$
156 | \bi
157 | \item Otherwise you need to find a more clever approach than complete search
158 | \ei
159 | \vspace{20pt}
160 | \ei
161 | \end{frame}
162 |
163 | % TODO: Example problem
164 |
165 | \begin{frame}[fragile]{Iterating through subsets}
166 | \bi
167 | \item Remember the bit representation of subsets?
168 | \item Each integer from $0$ to $2^n - 1$ represents a different subset of the set $\{1,2,\ldots,n\}$
169 | \item Just iterate through the integers
170 | \ei
171 |
172 | \begin{minted}{cpp}
173 | int n = 5;
174 | for (int subset = 0; subset < (1 << n); subset++) {
175 | for (int i = 0; i < n; i++) {
176 | if ((subset & (1 << i)) != 0) {
177 | printf("%d ", i+1);
178 | }
179 | }
180 | printf("\n");
181 | }
182 | \end{minted}
183 | \end{frame}
184 |
185 | \begin{frame}{Iterating through subsets}
186 | \bi
187 | \item Similar in Python
188 | \vspace{20pt}
189 | \item Remember that there are $2^n$ subsets of $n$ elements, so usually you can only go through all subsets if $n \leq 25$
190 | \bi
191 | \item Otherwise you need to find a more clever approach than complete search
192 | \ei
193 | \vspace{20pt}
194 | \ei
195 | \end{frame}
196 |
197 | % TODO: Example problem
198 |
199 | \begin{frame}[fragile]{Backtracking}
200 | \bi
201 | \item We've seen two ways to go through a complex search space, but both of the solutions were rather specific
202 | \item Would be nice to have a more general ``framework''
203 | \vspace{10pt}
204 | \item Backtracking!
205 | \ei
206 | \end{frame}
207 |
208 | \begin{frame}[fragile]{Backtracking}
209 | \bi
210 | \item Define states
211 | \bi
212 | \item We have one initial ``empty'' state
213 | \item Some states are partial
214 | \item Some states are complete
215 | \ei
216 | \vspace{10pt}
217 | \item Define transitions from a state to possible next states
218 | \vspace{10pt}
219 | \item Basic idea:
220 | \begin{enumerate}
221 | \item Start with the empty state
222 | \item Use recursion to traverse all states by going through the transitions
223 | \item If the current state is invalid, then stop exploring this branch
224 | \item Process all complete states (these are the states we're looking for)
225 | \end{enumerate}
226 | \ei
227 | \end{frame}
228 |
229 |
230 | \begin{frame}[fragile]{Backtracking}
231 | \bi
232 | \item General solution form:
233 | \ei
234 |
235 | \begin{minted}[fontsize=\scriptsize]{cpp}
236 | state S;
237 |
238 | void generate() {
239 | if (!is_valid(S))
240 | return;
241 |
242 | if (is_complete(S))
243 | print(S);
244 |
245 | foreach (possible next move P) {
246 | apply move P;
247 | generate();
248 | undo move P;
249 | }
250 | }
251 |
252 | S = empty state;
253 | generate();
254 | \end{minted}
255 | \end{frame}
256 |
257 |
258 | \begin{frame}[fragile]{Generating all subsets}
259 | \bi
260 | \item Also simple to do with backtracking:
261 | \ei
262 | \begin{minted}[fontsize=\tiny]{cpp}
263 | const int n = 5;
264 | bool pick[n];
265 |
266 | void generate(int at) {
267 | if (at == n) {
268 | for (int i = 0; i < n; i++) {
269 | if (pick[i]) {
270 | printf("%d ", i+1);
271 | }
272 | }
273 | printf("\n");
274 | } else {
275 |
276 | // either pick element no. at
277 | pick[at] = true;
278 | generate(at + 1);
279 |
280 | // or don't pick element no. at
281 | pick[at] = false;
282 | generate(at + 1);
283 | }
284 | }
285 |
286 | generate(0);
287 | \end{minted}
288 | \end{frame}
289 |
290 |
291 | \begin{frame}[fragile]{Generating all permutations}
292 | \bi
293 | \item Also simple to do with backtracking:
294 | \ei
295 | \begin{minted}[fontsize=\tiny]{cpp}
296 | const int n = 5;
297 | int perm[n];
298 | bool used[n];
299 |
300 | void generate(int at) {
301 | if (at == n) {
302 | for (int i = 0; i < n; i++) {
303 | printf("%d ", perm[i]+1);
304 | }
305 | printf("\n");
306 | } else {
307 |
308 | // decide what the at-th element should be
309 | for (int i = 0; i < n; i++) {
310 | if (!used[i]) {
311 | used[i] = true;
312 | perm[at] = i;
313 |
314 | generate(at + 1);
315 |
316 | // remember to undo the move:
317 | used[i] = false;
318 | }
319 | }
320 | }
321 | }
322 |
323 | memset(used, 0, n);
324 | generate(0);
325 | \end{minted}
326 | \end{frame}
327 |
328 | \begin{frame}[fragile]{$n$ queens}
329 | \bi
330 | \item Given $n$ queens and an $n\times n$ chessboard, find all ways to
331 | put the $n$ queens on the chessboard such that no queen can attack
332 | any other queen
333 |
334 | \vspace{10pt}
335 |
336 | \item This is a very specific set we want to iterate through, so we probably won't find this in the standard library
337 | \item We could use our bit trick to iterate through all subsets of the $n\times n$ cells of size $n$, but that would be very slow
338 | \vspace{20pt}
339 | \item Let's use backtracking
340 | \ei
341 | \end{frame}
342 |
343 | \begin{frame}[fragile]{$n$ queens}
344 | \bi
345 | \item Go through the cells in increasing order
346 | \item Either put a queen on that cell or not (transition)
347 | \item Don't put down a queen if she's able to attack another queen already on the table
348 | \ei
349 |
350 | \vspace{10pt}
351 |
352 | \begin{minted}{cpp}
353 | const int n = 8;
354 | bool has_queen[n][n];
355 | int queens_left = n;
356 |
357 | // generate function
358 |
359 | memset(has_queen, 0, sizeof(has_queen));
360 | generate(0, 0);
361 | \end{minted}
362 | \end{frame}
363 |
364 | \begin{frame}[fragile]{$n$ queens}
365 | \begin{minted}[fontsize=\tiny]{cpp}
366 | void generate(int x, int y) {
367 | if (y == n) {
368 | generate(x+1, 0);
369 | } else if (x == n) {
370 | if (queens_left == 0) {
371 | for (int i = 0; i < n; i++) {
372 | for (int j = 0; j < n; j++) {
373 | printf("%c", has_queen[i][j] ? 'Q' : '.');
374 | }
375 | printf("\n");
376 | }
377 | }
378 | } else {
379 |
380 | if (queens_left > 0 and no queen can attack cell (x,y)) {
381 | // try putting a queen on this cell
382 | has_queen[x][y] = true;
383 | queens_left--;
384 |
385 | generate(x, y+1);
386 |
387 | // undo the move
388 | has_queen[x][y] = false;
389 | queens_left++;
390 | }
391 |
392 | // try leaving this cell empty
393 | generate(x, y+1);
394 | }
395 | }
396 | \end{minted}
397 | \end{frame}
398 |
399 | % \begin{frame}{Example problem: The Hamming Distance Problem}
400 | % \bi
401 | % \item http://uva.onlinejudge.org/external/7/729.html
402 | % \ei
403 | % \end{frame}
404 | \begin{frame}{Example problem: Lucky Numbers}
405 | \bi
406 | \item https://open.kattis.com/problems/luckynumber
407 | \ei
408 | \end{frame}
409 |
410 | \section{Divide and conquer}
411 | \begin{frame}{Divide and conquer}
412 | \bi
413 | \item Given an instance of the problem, the basic idea is to
414 | \begin{enumerate}
415 | \item split the problem into one or more smaller subproblems
416 | \item solve each of these subproblems recursively
417 | \item combine the solutions to the subproblems into a solution of the given problem
418 | \end{enumerate}
419 |
420 | \vspace{10pt}
421 |
422 | \item Some standard divide and conquer algorithms:
423 | \bi
424 | \item Quicksort
425 | \item Mergesort
426 | \item Karatsuba algorithm
427 | \item Strassen algorithm
428 | \item Many algorithms from computational geometry
429 | \bi
430 | \item Convex hull
431 | \item Closest pair of points
432 | \ei
433 | \ei
434 | \ei
435 | \end{frame}
436 |
437 | \begin{frame}[fragile]{Divide and conquer: Time complexity}
438 | \begin{minted}[fontsize=\scriptsize]{cpp}
439 | void solve(int n) {
440 | if (n == 0)
441 | return;
442 |
443 | solve(n/2);
444 | solve(n/2);
445 |
446 | for (int i = 0; i < n; i++) {
447 | // some constant time operations
448 | }
449 | }
450 | \end{minted}
451 |
452 | \bi
453 | \item What is the time complexity of this divide and conquer algorithm?
454 | \item Usually helps to model the time complexity as a recurrence relation:
455 | \bi
456 | \item $T(n) = 2T(n/2) + n$
457 | \ei
458 | \ei
459 | \end{frame}
460 |
461 | \begin{frame}[fragile]{Divide and conquer: Time complexity}
462 | \bi
463 | \item But how do we solve such recurrences?
464 | \item Usually simplest to use the Master theorem when applicable
465 | \bi
466 | \item It gives a solution to a recurrence of the form $T(n) = aT(n/b) + f(n)$ in asymptotic terms
467 | \item All of the divide and conquer algorithms mentioned so far have a recurrence of this form
468 | \ei
469 | \vspace{10pt}
470 | \item The Master theorem tells us that $T(n) = 2T(n/2) + n$ has asymptotic time complexity $O(n \log n)$
471 | \vspace{10pt}
472 | \item You don't need to know the Master theorem for this course, but still recommended as it's very useful
473 | \ei
474 | \end{frame}
475 |
476 | \begin{frame}{Decrease and conquer}
477 | \bi
478 | \item Sometimes we're not actually dividing the problem into many subproblems, but only into one smaller subproblem
479 | \item Usually called decrease and conquer
480 | \item The most common example of this is binary search
481 | \ei
482 | \end{frame}
483 |
484 | \begin{frame}{Binary search}
485 | \bi
486 | \item We have a \textbf{sorted} array of elements, and we want to check if it contains a particular element $x$
487 | \vspace{5pt}
488 | \item Algorithm:
489 | \begin{enumerate}
490 | \item Base case: the array is empty, return false
491 | \item Compare $x$ to the element in the middle of the array
492 | \item If it's equal, then we found $x$ and we return true
493 | \item If it's less, then $x$ must be in the left half of the array
494 | \begin{enumerate}
495 | \item Binary search the element (recursively) in the left half
496 | \end{enumerate}
497 | \item If it's greater, then $x$ must be in the right half of the array
498 | \begin{enumerate}
499 | \item Binary search the element (recursively) in the right half
500 | \end{enumerate}
501 | \end{enumerate}
502 | \ei
503 | \end{frame}
504 |
505 | \begin{frame}[fragile]{Binary search}
506 | \begin{minted}[fontsize=\scriptsize]{cpp}
507 | bool binary_search(const vector &arr, int lo, int hi, int x) {
508 | if (lo > hi) {
509 | return false;
510 | }
511 |
512 | int m = (lo + hi) / 2;
513 | if (arr[m] == x) {
514 | return true;
515 | } else if (x < arr[m]) {
516 | return binary_search(arr, lo, m - 1, x);
517 | } else if (x > arr[m]) {
518 | return binary_search(arr, m + 1, hi, x);
519 | }
520 | }
521 |
522 | binary_search(arr, 0, arr.size() - 1, x);
523 | \end{minted}
524 |
525 | \bi
526 | \item $T(n) = T(n/2) + 1$
527 | \item $O(\log n)$
528 | \ei
529 | \end{frame}
530 |
531 | \begin{frame}[fragile]{Binary search - iterative}
532 | \begin{minted}[fontsize=\scriptsize]{cpp}
533 | bool binary_search(const vector &arr, int x) {
534 | int lo = 0,
535 | hi = arr.size() - 1;
536 |
537 | while (lo <= hi) {
538 | int m = (lo + hi) / 2;
539 | if (arr[m] == x) {
540 | return true;
541 | } else if (x < arr[m]) {
542 | hi = m - 1;
543 | } else if (x > arr[m]) {
544 | lo = m + 1;
545 | }
546 | }
547 |
548 | return false;
549 | }
550 | \end{minted}
551 | \end{frame}
552 |
553 | \begin{frame}{Binary search over integers}
554 | \bi
555 | \item This might be the most well known application of binary search, but it's far from being the only application
556 | \item More generally, we have a predicate $p : \{0,\ldots,n-1\} \rightarrow \{T, F\}$ which has the property that if $p(i) = T$, then $p(j) = T$ for all $j > i$
557 | \item Our goal is to find the smallest index $j$ such that $p(j) = T$ as quickly as possible
558 | \ei
559 |
560 | \begin{center}
561 | \begin{tabular}{ccccccccccccccccccc}
562 | $i$ & $0$ & $1$ & $\cdots$ & $j-1$ & \color{vhilight}{$j$} & $j+1$ & $\cdots$ & $n-2$ & $n-1$ \\
563 | \hline
564 | $p(i)$ & $F$ & $F$ & $\cdots$ & $F$ & \color{vhilight}{$T$} & $T$ & $\cdots$ & $T$ & $T$ \\
565 | \end{tabular}
566 | \end{center}
567 |
568 | \bi
569 | \item We can do this in $O(\log(n) \times f)$ time, where $f$ is the cost of evaluating the predicate $p$, in the same way as when we were binary searching an array
570 | \ei
571 | \end{frame}
572 |
573 | \begin{frame}[fragile]{Binary search over integers}
574 | \begin{minted}[fontsize=\footnotesize]{cpp}
575 | int lo = 0,
576 | hi = n - 1;
577 |
578 | while (lo < hi) {
579 | int m = (lo + hi) / 2;
580 |
581 | if (p(m)) {
582 | hi = m;
583 | } else {
584 | lo = m + 1;
585 | }
586 | }
587 |
588 | if (lo == hi && p(lo)) {
589 | printf("lowest index is %d\n", lo);
590 | } else {
591 | printf("no such index\n");
592 | }
593 | \end{minted}
594 | \end{frame}
595 |
596 | \begin{frame}[fragile]{Binary search over integers}
597 | \bi
598 | \item Find the index of $x$ in the sorted array $arr$
599 | \ei
600 | \begin{minted}{cpp}
601 | bool p(int i) {
602 | return arr[i] >= x;
603 | }
604 | \end{minted}
605 |
606 | \vspace{20pt}
607 | \bi
608 | \item Later we'll see how to use this in other ways
609 | \ei
610 | \end{frame}
611 |
612 | \begin{frame}[fragile]{Binary search over reals}
613 | \bi
614 | \item An even more general version of binary search is over the real numbers
615 | \item We have a predicate $p : [lo,hi] \rightarrow \{T, F\}$ which has the property that if $p(i) = T$, then $p(j) = T$ for all $j > i$
616 | \item Our goal is to find the smallest real number $j$ such that $p(j) = T$ as quickly as possible
617 |
618 | \vspace{5pt}
619 | \item Since we're working with real numbers (hypothetically), our $[lo,hi]$ can be halved infinitely many times without ever becoming a single real number
620 | \item Instead it will suffice to find a real number $j'$ that is very close to the correct answer $j$, say not further than $EPS = 2^{-30}$ away
621 |
622 | \vspace{5pt}
623 | \item We can do this in $O(\log(\frac{hi - lo}{EPS}))$ time in a similar way as when we were binary searching an array
624 | \ei
625 | \end{frame}
626 |
627 | \begin{frame}[fragile]{Binary search over reals}
628 | \begin{minted}{cpp}
629 | double EPS = 1e-10,
630 | lo = -1000.0,
631 | hi = 1000.0;
632 |
633 | while (hi - lo > EPS) {
634 | double mid = (lo + hi) / 2.0;
635 |
636 | if (p(mid)) {
637 | hi = mid;
638 | } else {
639 | lo = mid;
640 | }
641 | }
642 |
643 | printf("%0.10lf\n", lo);
644 | \end{minted}
645 | \end{frame}
646 |
647 | \begin{frame}[fragile]{Binary search over reals}
648 | \bi
649 | \item This has many cool numerical applications
650 | \vspace{5pt}
651 | \item Find the square root of $x$
652 | \ei
653 | \begin{minted}{cpp}
654 | bool p(double j) {
655 | return j*j >= x;
656 | }
657 | \end{minted}
658 | \bi
659 | \item Find the root of an increasing function $f(x)$
660 | \ei
661 | \begin{minted}{cpp}
662 | bool p(double x) {
663 | return f(x) >= 0.0;
664 | }
665 | \end{minted}
666 |
667 | \bi
668 | \item This is also referred to as the Bisection method
669 | \ei
670 | \end{frame}
671 |
672 | % TODO: Example problem
673 |
674 | \begin{frame}{Example problem}
675 | \bi
676 | \item Problem C from NWERC 2006: Pie
677 | \ei
678 | \end{frame}
679 |
680 | \begin{frame}{Binary search the answer}
681 | \bi
682 | \item It may be hard to find the optimal solution directly, as we saw in the example problem
683 | \item On the other hand, it may be easy to check if some $x$ is a solution or not
684 | \vspace{5pt}
685 | \item A method of using binary search to find the minimum or maximum solution to a problem
686 | \item Only applicable when the problem has the binary search property: if $i$ is a solution, then so are all $j > i$
687 | \vspace{5pt}
688 | \item $p(i)$ checks whether $i$ is a solution, then we simply apply binary search on $p$ to get the minimum or maximum solution
689 | \ei
690 | \end{frame}
691 |
692 | % TODO: Add ternary search?
693 |
694 | \begin{frame}{Other types of divide and conquer}
695 | \bi
696 | \item Binary search is very useful, can be used to construct simple and efficient solutions to problems
697 | \item But binary search is only one example of divide and conquer
698 | \item Let's explore two more examples
699 | \ei
700 | \end{frame}
701 |
702 | \begin{frame}[fragile]{Binary exponentiation}
703 | \bi
704 | \item We want to calculate $x^n$, where $x,n$ are integers
705 | \item Assume we don't have the built-in \texttt{pow} method
706 | \item Naive method:
707 | \ei
708 |
709 | \begin{minted}{cpp}
710 | int pow(int x, int n) {
711 | int res = 1;
712 | for (int i = 0; i < n; i++) {
713 | res = res * x;
714 | }
715 |
716 | return res;
717 | }
718 | \end{minted}
719 |
720 | \bi
721 | \item This is $O(n)$, but what if we want to support large $n$ efficiently?
722 | \ei
723 | \end{frame}
724 |
725 | \begin{frame}{Binary exponentiation}
726 | \bi
727 | \item Let's use divide and conquer
728 | \vspace{10pt}
729 | \item Notice the three identities:
730 |
731 | \bi
732 | \item $x^0 = 1$
733 | \item $x^n = x \times x^{n-1}$
734 | \item $x^n = x^{n/2} \times x^{n/2}$
735 | \ei
736 |
737 | \item Or in terms of our function:
738 |
739 | \bi
740 | \item $pow(x,0) = 1$
741 | \item $pow(x,n) = x \times pow(x, n-1)$
742 | \item $pow(x,n) = pow(x, n/2) \times pow(x, n/2)$
743 | \ei
744 |
745 | \item $pow(x,n/2)$ is used twice, but we only need to compute it once:
746 |
747 | \bi
748 | \item $pow(x,n) = pow(x, n/2)^2$
749 | \ei
750 | \ei
751 | \end{frame}
752 |
753 | \begin{frame}[fragile]{Binary exponentiation}
754 | \bi
755 | \item Let's try using these identities to compute the answer recursively
756 | \ei
757 |
758 | \vspace{10pt}
759 |
760 | \begin{minted}{cpp}
761 | int pow(int x, int n) {
762 | if (n == 0) return 1;
763 | return x * pow(x, n - 1);
764 | }
765 | \end{minted}
766 |
767 | \vspace{10pt}
768 |
769 | \bi
770 | \item<2-> How efficient is this?
771 | \bi
772 | \item $T(n) = 1 + T(n-1)$
773 | \item<3-> $O(n)$
774 | \item<4-> Still just as slow...
775 | \ei
776 | \ei
777 |
778 | \end{frame}
779 |
780 | \begin{frame}[fragile]{Binary exponentiation}
781 | \bi
782 | \item What about the third identity?
783 | \bi
784 | \item $n/2$ is not an integer when $n$ is odd, so let's only use it when $n$ is even
785 | \ei
786 | \ei
787 |
788 | \begin{minted}{cpp}
789 | int pow(int x, int n) {
790 | if (n == 0) return 1;
791 | if (n % 2 != 0) return x * pow(x, n - 1);
792 | int st = pow(x, n/2);
793 | return st * st;
794 | }
795 | \end{minted}
796 |
797 | \bi
798 | \item How efficient is this?
799 | \bi
800 | \item<2-> $T(n) = 1 + T(n-1)$ if $n$ is odd
801 | \item<2-> $T(n) = 1 + T(n/2)$ if $n$ is even
802 | \item<3-> Since $n-1$ is even when $n$ is odd:
803 | \item<3-> $T(n) = 1 + 1 + T((n-1)/2)$ if $n$ is odd
804 | \item<4-> $O(\log n)$
805 | \item<4-> Fast!
806 | \ei
807 | \ei
808 | \end{frame}
809 |
810 | \begin{frame}{Binary exponentiation}
811 | \bi
812 | \item Notice that $x$ doesn't have to be an integer, and $\star$ doesn't have to be integer multiplication...
813 | \item It also works for:
814 | \bi
815 | \item Computing $x^n$, where $x$ is a floating point number and $\star$ is floating point number multiplication
816 | \item Computing $A^n$, where $A$ is a matrix and $\star$ is matrix multiplication
817 | \item Computing $x^n \pmod{m}$, where $x$ is an integer and $\star$ is integer multiplication modulo $m$
818 | \item Computing $x\star x\star \cdots \star x$, where $x$ is any element and $\star$ is any associative operator
819 | \ei
820 |
821 | \item All of these can be done in $O(\log(n) \times f)$, where $f$ is the cost of doing one application of the $\star$ operator
822 | \ei
823 | \end{frame}
824 |
825 | \begin{frame}{Fibonacci words}
826 | \bi
827 | \item Recall that the Fibonacci sequence can be defined as follows:
828 | \bi
829 | \item $\mathrm{fib}_1 = 1$
830 | \item $\mathrm{fib}_2 = 1$
831 | \item $\mathrm{fib}_n = \mathrm{fib}_{n-2} + \mathrm{fib}_{n-1}$
832 | \ei
833 | \item We get the sequence $1, 1, 2, 3, 5, 8, 13, 21, \ldots$
834 | \vspace{10pt}
835 | \item There are many generalizations of the Fibonacci sequence
836 | \item One of them is to start with other numbers, like:
837 | \bi
838 | \item $f_1 = 5$
839 | \item $f_2 = 4$
840 | \item $f_n = f_{n-2} + f_{n-1}$
841 | \ei
842 | \item We get the sequence $5, 4, 9, 13, 22, 35, 57, \ldots$
843 | \vspace{10pt}
844 | \item What if we start with something other than numbers?
845 | \ei
846 | \end{frame}
847 |
848 | \begin{frame}{Fibonacci words}
849 | \bi
850 | \item Let's try starting with a pair of strings, and let $+$ denote string concatenation:
851 | \bi
852 | \item $g_1 = A$
853 | \item $g_2 = B$
854 | \item $g_n = g_{n-2} + g_{n-1}$
855 | \ei
856 | \vspace{10pt}
857 | \item Now we get the sequence of strings:
858 | \bi
859 | \item $A$
860 | \item $B$
861 | \item $AB$
862 | \item $BAB$
863 | \item $ABBAB$
864 | \item $BABABBAB$
865 | \item $ABBABBABABBAB$
866 | \item $BABABBABABBABBABABBAB$
867 | \item $\ldots$
868 | \ei
869 | \ei
870 | \end{frame}
871 |
872 | \begin{frame}{Fibonacci words}
873 | \bi
874 | \item How long is $g_n$?
875 | \bi
876 | \item $\mathrm{len}(g_1) = 1$
877 | \item $\mathrm{len}(g_2) = 1$
878 | \item $\mathrm{len}(g_n) = \mathrm{len}(g_{n-2}) + \mathrm{len}(g_{n-1})$
879 | \ei
880 | \vspace{5pt}
881 | \item Looks familiar?
882 | \vspace{2pt}
883 | \item $\mathrm{len}(g_n) = \mathrm{fib}_{n}$
884 | \vspace{10pt}
885 | \item So the strings become very large very quickly
886 | \bi
887 | \item $\mathrm{len}(g_{10}) = 55$
888 | \item $\mathrm{len}(g_{100}) = 354224848179261915075$
889 | \item $\mathrm{len}(g_{1000}) = $ \begin{align*}
890 | &434665576869374564356885276750406258025646605173717\\
891 | &804024817290895365554179490518904038798400792551692\\
892 | &959225930803226347752096896232398733224711616429964\\
893 | &409065331879382989696499285160037044761377951668492\\
894 | &28875
895 | \end{align*}
896 |
897 | \ei
898 | \ei
899 | \end{frame}
900 |
901 | \begin{frame}{Example problem: Batmanacci}
902 | \bi
903 | \item https://open.kattis.com/problems/batmanacci
904 | \ei
905 | \end{frame}
906 |
907 | \begin{frame}{Fibonacci words}
908 | \bi
909 | \item Task: Compute the $i$th character in $g_{n}$
910 | \vspace{10pt}
911 | \item<2-> Simple to do in $O(\mathrm{len}(n))$, but that is extremely slow for large $n$
912 | \vspace{10pt}
913 | \item<3-> Can be done in $O(n)$ using divide and conquer
914 | \ei
915 | \end{frame}
916 |
917 | \end{document}
918 |
919 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/batmanacci.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 |
13 | long long len[100100];
14 |
15 | char get(long long n, long long k) {
16 | if (n == 1) {
17 | // N
18 | return 'N';
19 | } else if (n == 2) {
20 | return 'A';
21 | } else {
22 | long long L = len[n-2];
23 | if (k <= L) {
24 | return get(n-2, k);
25 | } else {
26 | return get(n-1, k-L);
27 | }
28 | }
29 | }
30 |
31 | int main() {
32 | len[1] = 1;
33 | len[2] = 1;
34 | for (int i = 3; i < 100100; i++) {
35 | len[i] = len[i-2] + len[i-1];
36 | if (len[i] > 1000000000000000000)
37 | len[i] = 1000000000000000001;
38 | }
39 |
40 | long long n, k;
41 | cin >> n >> k;
42 |
43 | cout << get(n, k) << endl;
44 |
45 | return 0;
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/bsearch2.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | double f(double x) {
13 | return 3*x - 10;
14 | }
15 |
16 | bool p(double i) {
17 | return f(i) >= 0;
18 | }
19 |
20 | int main() {
21 |
22 | double EPS = 1e-10,
23 | lo = -1000.0,
24 | hi = 1000.0;
25 | while (hi - lo > EPS) {
26 | double mid = (lo + hi) / 2.0;
27 | if (p(mid)) {
28 | hi = mid;
29 | } else {
30 | lo = mid;
31 | }
32 | }
33 | printf("%0.10lf\n", lo);
34 |
35 | return 0;
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/closestsums.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | int main() {
13 | int n, m;
14 | int ts = 0;
15 | while (cin >> n) {
16 | printf("Case %d:\n", ++ts);
17 | vi arr(n);
18 | rep(i,0,n) {
19 | cin >> arr[i];
20 | }
21 | cin >> m;
22 | rep(i,0,m) {
23 | int x;
24 | cin >> x;
25 | int best = 1323;
26 | bool found = false;
27 | for (int j = 0; j < n; j++) {
28 | for (int k = j+1; k
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | int n;
13 | vector number;
14 | void generate(int k) {
15 |
16 | if (k > 0) {
17 | stringstream ss;
18 | for (int i = 0; i < k; i++) {
19 | ss << number[i];
20 | }
21 | int x;
22 | ss >> x;
23 | if (x % k != 0) {
24 | return;
25 | }
26 | }
27 |
28 | if (k == n) {
29 | for (int i = 0; i < n; i++) {
30 | cout << number[i];
31 | }
32 | cout << endl;
33 | } else {
34 | for (int d = 0; d <= 9; d++) {
35 | if (k == 0 && d == 0) {
36 | continue;
37 | }
38 | number.push_back(d);
39 | generate(k+1);
40 | number.pop_back();
41 | }
42 | }
43 | }
44 |
45 |
46 | int main() {
47 | cin >> n;
48 |
49 | generate(0);
50 |
51 | return 0;
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/04_problem_solving_paradigms/pie2.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 | const double pi = acos(-1.0);
13 | int n, f;
14 | vector rad;
15 |
16 | double F(double x) {
17 | double cnt = 0;
18 | for (int i = 0; i < size(rad); i++) {
19 | double v = rad[i] * rad[i] * pi;
20 | cnt += floor(v/x);
21 | }
22 | return cnt;
23 | }
24 |
25 | int main() {
26 | int ts;
27 | cin >> ts;
28 | rep(t,0,ts) {
29 | cin >> n >> f;
30 | rad.clear();
31 | rep(i,0,n) {
32 | double r;
33 | cin >> r;
34 | rad.push_back(r);
35 | }
36 |
37 | double EPS = 1e-10,
38 | lo = 0,
39 | hi = 1e9;
40 | while (hi - lo > EPS) {
41 | double mid = (lo + hi) / 2.0;
42 | if (F(mid) < f + 1) {
43 | hi = mid;
44 | } else {
45 | lo = mid;
46 | }
47 | }
48 |
49 | cout << setprecision(10) << fixed << lo << endl;
50 | }
51 |
52 | return 0;
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/05_greedy_algorithms/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 5: Greedy algorithms
2 | Introduces greedy algorithms, and covers coin changing, interval scheduling, and scheduling to minimize lateness.
3 |
4 | Material
5 |
6 | - Lecture slides: PDF
7 |
8 | Problems
9 | Solve some of the following problems on Kattis. You need 3 points to get full score.
10 |
17 | Bonus problems
18 | If you want a challenge, you can try solving the following bonus problems.
19 |
23 |
--------------------------------------------------------------------------------
/05a_problem_session_1/README.md:
--------------------------------------------------------------------------------
1 | # Problem session 1
2 |
3 | Teams of up to three students had to solve the following problems. They had three hours, and were only allowed to use a single computer.
4 |
12 |
--------------------------------------------------------------------------------
/06_dynamic_programming/README.md:
--------------------------------------------------------------------------------
1 | # Lecture 6: Dynamic programming
2 |
3 | Introduces dynamic programming and goes over some examples.
4 |
5 | Problems
6 | Solve some of the following problems on Kattis. You need 3 points to get full score.
7 |
14 | Bonus problems
15 | If you want a challenge, you can try solving the following bonus problems.
16 |
20 |
--------------------------------------------------------------------------------
/06_dynamic_programming/aflv_06_dynamic_programming.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/06_dynamic_programming/aflv_06_dynamic_programming.pdf
--------------------------------------------------------------------------------
/06_dynamic_programming/aflv_06_dynamic_programming.tex:
--------------------------------------------------------------------------------
1 | \documentclass[10pt]{beamer}
2 | \usepackage[utf8]{inputenc}
3 | \usepackage[T1]{fontenc}
4 | \usetheme{metropolis}
5 | \usepackage{booktabs}
6 | \usepackage[scale=2]{ccicons}
7 | \usepackage{pgfplots}
8 | \usepgfplotslibrary{dateplot}
9 | \usepackage{xspace}
10 | \usepackage{pbox}
11 |
12 | % a few macros
13 | \newcommand{\bi}{\begin{itemize}}
14 | \newcommand{\ei}{\end{itemize}}
15 | \newcommand{\be}{\begin{enumerate}}
16 | \newcommand{\ee}{\end{enumerate}}
17 | \newcommand{\ig}{\includegraphics}
18 | \definecolor{hilight}{RGB}{235,129,27}
19 | \definecolor{vhilight}{RGB}{235,129,27}
20 |
21 | % title info
22 | \title{Dynamic Programming}
23 | \author{Bjarki Ágúst Guðmundsson\\ Tómas Ken Magnússon}
24 | \institute{\href{http://ru.is/td}{School of Computer Science} \\[2pt] \href{http://ru.is}{Reykjavík University}}
25 | \titlegraphic{\hfill\includegraphics[height=0.6cm]{kattis}}
26 | \date{\textbf{Árangursrík forritun og lausn verkefna}}
27 |
28 | % Tikz
29 | \usepackage{tikz}
30 | \usetikzlibrary{arrows,shapes}
31 |
32 | % Minted
33 | \usepackage{minted}
34 | \usemintedstyle{manni}
35 | \newminted{cpp}{fontsize=\footnotesize}
36 |
37 | % Graph styles
38 | \tikzstyle{vertex}=[circle,fill=black!50,minimum size=15pt,inner sep=0pt, font=\small]
39 | \tikzstyle{selected vertex} = [vertex, fill=red!24]
40 | \tikzstyle{edge} = [draw,thick,-]
41 | \tikzstyle{dedge} = [draw,thick,->]
42 | \tikzstyle{weight} = [font=\scriptsize,pos=0.5]
43 | \tikzstyle{selected edge} = [draw,line width=2pt,-,red!50]
44 | \tikzstyle{ignored edge} = [draw,line width=5pt,-,black!20]
45 |
46 | \tikzset{
47 | treenode/.style = {align=center, inner sep=0pt, text centered,
48 | font=\sffamily},
49 | vertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=black, text width=1.8em},% arbre rouge noir, noeud noir
50 | rvertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=red, text width=1.8em},% arbre rouge noir, noeud noir
51 | }
52 |
53 | \begin{document}
54 | \maketitle
55 |
56 |
57 | \begin{frame}{Today we're going to cover}
58 | \vspace{40pt}
59 | \bi
60 | \item Dynamic Programming
61 | \ei
62 | \end{frame}
63 |
64 | \begin{frame}{What is dynamic programming?}
65 | \bi
66 | \item A problem solving paradigm
67 | \item Similar in some respects to both divide and conquer and backtracking
68 | \vspace{5pt}
69 | \item Divide and conquer recap:
70 | \bi
71 | \item Split the problem into \textit{independent} subproblems
72 | \item Solve each subproblem recursively
73 | \item Combine the solutions to subproblems into a solution for the given problem
74 | \ei
75 | \vspace{5pt}
76 | \item Dynamic programming:
77 | \bi
78 | \item Split the problem into \textit{overlapping} subproblems
79 | \item Solve each subproblem recursively
80 | \item Combine the solutions to subproblems into a solution for the given problem
81 | \item \textit{Don't compute the answer to the same subproblem more than once}
82 | \ei
83 | \ei
84 | \end{frame}
85 |
86 | \begin{frame}[fragile]{Dynamic programming formulation}
87 | \vspace{30pt}
88 | \be
89 | \item Formulate the problem in terms of smaller versions of the problem (recursively)
90 | \item Turn this formulation into a recursive function
91 | \item Memoize the function (remember results that have been computed)
92 | \ee
93 | \end{frame}
94 |
95 | \begin{frame}[fragile]{Dynamic programming formulation}
96 | \begin{minted}[fontsize=\footnotesize]{cpp}
97 | map memory;
98 |
99 | value dp(problem P) {
100 | if (is_base_case(P)) {
101 | return base_case_value(P);
102 | }
103 |
104 | if (memory.find(P) != memory.end()) {
105 | return memory[P];
106 | }
107 |
108 | value result = some value;
109 | for (problem Q in subproblems(P)) {
110 | result = combine(result, dp(Q));
111 | }
112 |
113 | memory[P] = result;
114 | return result;
115 | }
116 | \end{minted}
117 | \end{frame}
118 |
119 | \begin{frame}{The Fibonacci sequence}
120 | \vspace{5pt}
121 | \textit{The first two numbers in the Fibonacci sequence are 1 and 1. All
122 | other numbers in the sequence are defined as the sum of the previous two
123 | numbers in the sequence.}
124 |
125 | \vspace{5pt}
126 | \bi
127 | \item Task: Find the $n$th number in the Fibonacci sequence
128 | \item Let's solve this with dynamic programming
129 | \ei
130 |
131 | \vspace{5pt}
132 | \be
133 | \item Formulate the problem in terms of smaller versions of the problem (recursively)
134 | \ee
135 |
136 | \begin{align*}
137 | \mathrm{fibonacci}(1) &= 1\\
138 | \mathrm{fibonacci}(2) &= 1\\
139 | \mathrm{fibonacci}(n) &= \mathrm{fibonacci}(n - 2) + \mathrm{fibonacci}(n - 1)
140 | \end{align*}
141 | \end{frame}
142 |
143 | \begin{frame}[fragile]{The Fibonacci sequence}
144 | \be
145 | \item[2.] Turn this formulation into a recursive function
146 | \ee
147 |
148 | \begin{minted}[fontsize=\footnotesize]{cpp}
149 | int fibonacci(int n) {
150 | if (n <= 2) {
151 | return 1;
152 | }
153 |
154 | int res = fibonacci(n - 2) + fibonacci(n - 1);
155 |
156 | return res;
157 | }
158 | \end{minted}
159 | \end{frame}
160 |
161 | \begin{frame}[fragile]{The Fibonacci sequence}
162 | \bi
163 | \item What is the time complexity of this? \onslide<2->{Exponential, almost $O(2^n)$}
164 | \ei
165 |
166 | \begin{figure}
167 |
168 | \begin{tikzpicture}
169 |
170 | [-,thick,%
171 | every node/.style={shape=circle,draw,thick},%
172 | level distance=0.5cm,
173 | growth parent anchor={south}, nodes={anchor=north},
174 | scale=0.8,%
175 | ]
176 | \scriptsize
177 | \node {$fib(6)$}
178 | [sibling distance=5cm]
179 | child {node {$fib(4)$}
180 | [sibling distance=2cm]
181 | child {node {$fib(2)$}
182 | % [sibling distance=0.5cm]
183 | % % child {node {$0$}}
184 | % child {node {$fib(1)$}
185 | % % child {node {$0$}}
186 | % % child {node {$0$}}
187 | % }
188 | }
189 | child {node {$fib(3)$}
190 | [sibling distance=1cm]
191 | child {node {$fib(1)$}
192 | [sibling distance=0.5cm]
193 | % child {node {$0$}}
194 | % child {node {$0$}}
195 | }
196 | child {node {$fib(2)$}
197 | % [sibling distance=0.5cm]
198 | % % child {node {$0$}}
199 | % child {node {$fib(1)$}
200 | % % child {node {$0$}}
201 | % % child {node {$0$}}
202 | % }
203 | }
204 | }
205 | }
206 | child {node {$fib(5)$}
207 | [sibling distance=3cm]
208 | child {node {$fib(3)$}
209 | [sibling distance=1cm]
210 | child {node {$fib(1)$}
211 | [sibling distance=0.5cm]
212 | % child {node {$0$}}
213 | % child {node {$0$}}
214 | }
215 | child {node {$fib(2)$}
216 | % [sibling distance=0.5cm]
217 | % % child {node {$0$}}
218 | % child {node {$fib(1)$}
219 | % % child {node {$0$}}
220 | % % child {node {$0$}}
221 | % }
222 | }
223 | }
224 | child {node {$fib(4)$}
225 | [sibling distance=2cm]
226 | child {node {$fib(2)$}
227 | % [sibling distance=0.5cm]
228 | % % child {node {$0$}}
229 | % child {node {$fib(1)$}
230 | % % child {node {$0$}}
231 | % % child {node {$0$}}
232 | % }
233 | }
234 | child {node {$fib(3)$}
235 | [sibling distance=1cm]
236 | child {node {$fib(1)$}
237 | [sibling distance=0.5cm]
238 | % child {node {$0$}}
239 | % child {node {$0$}}
240 | }
241 | child {node {$fib(2)$}
242 | % [sibling distance=0.5cm]
243 | % % child {node {$0$}}
244 | % child {node {$fib(1)$}
245 | % % child {node {$0$}}
246 | % % child {node {$0$}}
247 | % }
248 | }
249 | }
250 | }
251 | };
252 | \end{tikzpicture}
253 |
254 | % \tikzset{
255 | % treenode/.style = {align=center, inner sep=0pt, text centered,
256 | % font=\sffamily},
257 | % vertex/.style = {treenode, circle, white, font=\sffamily\bfseries\tiny, draw=white,
258 | % text width=1.8em},% arbre rouge noir, noeud noir
259 | % }
260 | %
261 | % \begin{tikzpicture}
262 | % [->,>=stealth',level/.style={sibling distance = 5cm/#1,
263 | % level distance = 1.8cm},scale=0.8]
264 | % \node [vertex] {fib(10)}
265 | % child{ node [vertex] {fib(8)}
266 | % child{ node [vertex] {fib(6)}
267 | % child{ node [vertex] {fib(4)} }
268 | % child{ node [vertex] {fib(5)}}
269 | % }
270 | % child{ node [vertex] {fib(7)}
271 | % child{ node [vertex] {fib(5)}}
272 | % child{ node [vertex] {fib(6)}}
273 | % }
274 | % }
275 | % child{ node [vertex] {fib(9)}
276 | % child{ node [vertex] {fib(7)}
277 | % child{
278 | % node [vertex] {fib(5)}
279 | % child { node [vertex] {fib(3)} }
280 | % child { node [vertex] {fib(4)} }
281 | % }
282 | % child{ node [vertex] {fib(6)}
283 | % }
284 | % }
285 | % child{ node [vertex] {fib(8)}
286 | % child{ node [vertex] {49}}
287 | % % child{ node [vertex] {}}
288 | % }
289 | % }
290 | % ;
291 | % \end{tikzpicture}
292 | \end{figure}
293 |
294 | \end{frame}
295 |
296 | \begin{frame}[fragile]{The Fibonacci sequence}
297 | \be
298 | \item[3.] Memoize the function (remember results that have been computed)
299 | \ee
300 |
301 | \vspace{5pt}
302 |
303 | \begin{minted}[fontsize=\footnotesize]{cpp}
304 | map mem;
305 |
306 | int fibonacci(int n) {
307 | if (n <= 2) {
308 | return 1;
309 | }
310 |
311 | if (mem.find(n) != mem.end()) {
312 | return mem[n];
313 | }
314 |
315 | int res = fibonacci(n - 2) + fibonacci(n - 1);
316 |
317 | mem[n] = res;
318 | return res;
319 | }
320 | \end{minted}
321 |
322 | \end{frame}
323 |
324 | \begin{frame}[fragile]{The Fibonacci sequence}
325 | \vspace{5pt}
326 |
327 | \begin{minted}[fontsize=\footnotesize]{cpp}
328 | int mem[1000];
329 | for (int i = 0; i < 1000; i++)
330 | mem[i] = -1;
331 |
332 | int fibonacci(int n) {
333 | if (n <= 2) {
334 | return 1;
335 | }
336 |
337 | if (mem[n] != -1) {
338 | return mem[n];
339 | }
340 |
341 | int res = fibonacci(n - 2) + fibonacci(n - 1);
342 |
343 | mem[n] = res;
344 | return res;
345 | }
346 | \end{minted}
347 |
348 | \end{frame}
349 |
350 | \begin{frame}{The Fibonacci sequence}
351 | \bi
352 | \item What is the time complexity now?
353 | \vspace{5pt}
354 | \item We have $n$ possible inputs to the function: $1$, $2$, \ldots, $n$.
355 | \item Each input will either:
356 | \bi
357 | \item be computed, and the result saved
358 | \item be returned from memory
359 | \ei
360 | \item Each input will be computed at most once
361 | \item Time complexity is $O(n \times f)$, where $f$ is the time complexity of computing an input if we assume that the recursive calls are returned directly from memory ($O(1)$)
362 | \item Since we're only doing constant amount of work to compute the answer to an input, $f = O(1)$
363 | \item Total time complexity is $O(n)$
364 | \ei
365 | \end{frame}
366 |
367 | \begin{frame}{Maximum sum}
368 |
369 | \vspace{10pt}
370 |
371 | \bi
372 | \item Given an array $\mathrm{arr}[0]$, $\mathrm{arr}[1]$, \ldots, $\mathrm{arr}[n-1]$ of integers, find the interval with the highest sum
373 | \ei
374 |
375 | \begin{center}
376 | \begin{tabular}{|c|c|c|c|c|c|c|}
377 | \hline
378 | -15 & \color<2->{vhilight}{8} & \color<2->{vhilight}{-2} & \color<2->{vhilight}{1} & \color<2->{vhilight}{0} & \color<2->{vhilight}{6} & -3 \\
379 | \hline
380 | \end{tabular}
381 | \end{center}
382 |
383 | \bi
384 | \item<2-> The maximum sum of an interval in this array is $13$
385 |
386 | \item<3-> But how do we solve this in general?
387 | \bi
388 | \item Easy to loop through all $\approx n^2$ intervals, and calculate their sums, but that is $O(n^3)$
389 | \item We could use our static range sum trick to get this down to $O(n^2)$
390 | \item Can we do better with dynamic programming?
391 | \ei
392 | \ei
393 |
394 | \end{frame}
395 |
396 | \begin{frame}{Maximum sum}
397 |
398 | \vspace{20pt}
399 |
400 | \bi
401 | \item First step is to formulate this recursively
402 | \vspace{5pt}
403 | \item Let $\mathrm{max\_{}sum}(i)$ be the maximum sum interval in the range $0,\ldots,i$
404 | \vspace{5pt}
405 | \item Base case: $\mathrm{max\_{}sum}(0) = \mathrm{max}(0, arr[0])$
406 | \vspace{5pt}
407 | \item What about $\mathrm{max\_{}sum}(i)$?
408 | \item What does $\mathrm{max\_{}sum}(i-1)$ return?
409 | \item Is it possible to combine solutions to subproblems with smaller $i$ into a solution for $i$?
410 | \vspace{5pt}
411 | \item At least it's not obvious...
412 | \ei
413 |
414 | \end{frame}
415 |
416 | \begin{frame}{Maximum sum}
417 |
418 | \vspace{20pt}
419 |
420 | \bi
421 | \item Let's try changing perspective
422 | \vspace{5pt}
423 | \item Let $\mathrm{max\_{}sum}(i)$ be the maximum sum interval in the range $0,\ldots,i$, \textit{that ends at $i$}
424 | \vspace{5pt}
425 | \item Base case: $\mathrm{max\_{}sum}(0) = arr[0]$
426 | \vspace{5pt}
427 | \item $\mathrm{max\_{}sum}(i) = \mathrm{max}(arr[i], arr[i] + \mathrm{max\_{}sum}(i - 1))$
428 | \vspace{15pt}
429 | \item Then the answer is just $\mathrm{max}_{\ 0 \leq i < n}\ \{\ \mathrm{max\_{}sum}(i)\ \}$
430 | \ei
431 |
432 | \end{frame}
433 |
434 | \begin{frame}[fragile]{Maximum sum}
435 | \bi
436 | \item Next step is to turn this into a function
437 | \ei
438 |
439 | \begin{minted}{cpp}
440 | int arr[1000];
441 |
442 | int max_sum(int i) {
443 | if (i == 0) {
444 | return arr[i];
445 | }
446 |
447 | int res = max(arr[i], arr[i] + max_sum(i - 1));
448 |
449 | return res;
450 | }
451 | \end{minted}
452 | \end{frame}
453 |
454 | \begin{frame}[fragile]{Maximum sum}
455 | \bi
456 | \item Final step is to memoize the function
457 | \ei
458 |
459 | \begin{minted}[fontsize=\scriptsize]{cpp}
460 | int arr[1000];
461 | int mem[1000];
462 | bool comp[1000];
463 | memset(comp, 0, sizeof(comp));
464 |
465 | int max_sum(int i) {
466 | if (i == 0) {
467 | return arr[i];
468 | }
469 | if (comp[i]) {
470 | return mem[i];
471 | }
472 |
473 | int res = max(arr[i], arr[i] + max_sum(i - 1));
474 |
475 | mem[i] = res;
476 | comp[i] = true;
477 | return res;
478 | }
479 | \end{minted}
480 | \end{frame}
481 |
482 | \begin{frame}[fragile]{Maximum sum}
483 | \bi
484 | \item Then the answer is just the maximum over all interval ends
485 | \ei
486 |
487 | \begin{minted}{cpp}
488 | int maximum = 0;
489 | for (int i = 0; i < n; i++) {
490 | maximum = max(maximum, best_sum(i));
491 | }
492 |
493 | printf("%d\n", maximum);
494 | \end{minted}
495 | \end{frame}
496 |
497 | \begin{frame}[fragile]{Maximum sum}
498 | \vspace{40pt}
499 | \bi
500 | \item If you want to find the maximum sum interval in multiple arrays, remember to clear the memory in between
501 | \ei
502 | \end{frame}
503 |
504 | \begin{frame}{Maximum sum}
505 | \vspace{20pt}
506 | \bi
507 | \item What about time complexity?
508 | \vspace{5pt}
509 | \item There are $n$ possible inputs to the function
510 | \item Each input is processed in $O(1)$ time, assuming recursive calls are $O(1)$
511 | \item Time complexity is $O(n)$
512 | \ei
513 | \end{frame}
514 |
515 | \begin{frame}{Coin change}
516 | \vspace{20pt}
517 |
518 | \bi
519 | \item Given an array of coin denominations $d_0$, $d_1$, \ldots, $d_{n-1}$,
520 | and some amount $x$: What is minimum number of coins needed to
521 | represent the value $x$?
522 |
523 | \item Remember the greedy algorithm for Coin change?
524 | \item It didn't always give the optimal solution, and sometimes it didn't even give a solution at all...
525 |
526 | \vspace{10pt}
527 | \item What about dynamic programming?
528 | \ei
529 | \end{frame}
530 |
531 | \begin{frame}{Coin change}
532 | \bi
533 | \item First step: formulate the problem recursively
534 | \vspace{20pt}
535 | \item Let $\mathrm{opt}(i,x)$ denote the minimum number of coins needed to represent the value $x$ if we're only allowed to use coin denominations $d_0$, \ldots, $d_i$
536 | \vspace{10pt}
537 | \item Base case: $\mathrm{opt}(i,x) = \infty$ if $x < 0$
538 | \item Base case: $\mathrm{opt}(i,0) = 0$
539 | \item Base case: $\mathrm{opt}(-1,x) = \infty$
540 | \vspace{10pt}
541 | \item $\mathrm{opt}(i,x) = \mathrm{min} \left\{
542 | \begin{array}{l}
543 | 1 + \mathrm{opt}(i, x - d_i) \\
544 | \mathrm{opt}(i-1, x)
545 | \end{array}
546 | \right.$
547 | \ei
548 | \end{frame}
549 |
550 | \begin{frame}[fragile]{Coin change}
551 | \begin{minted}[fontsize=\footnotesize]{cpp}
552 | int INF = 100000;
553 | int d[10];
554 |
555 | int opt(int i, int x) {
556 | if (x < 0) return INF;
557 | if (x == 0) return 0;
558 | if (i == -1) return INF;
559 |
560 | int res = INF;
561 | res = min(res, 1 + opt(i, x - d[i]));
562 | res = min(res, opt(i - 1, x));
563 |
564 | return res;
565 | }
566 | \end{minted}
567 | \end{frame}
568 |
569 | \begin{frame}[fragile]{Coin change}
570 | \begin{minted}[fontsize=\footnotesize]{cpp}
571 | int INF = 100000;
572 | int d[10];
573 | int mem[10][10000];
574 | memset(mem, -1, sizeof(mem));
575 |
576 | int opt(int i, int x) {
577 | if (x < 0) return INF;
578 | if (x == 0) return 0;
579 | if (i == -1) return INF;
580 |
581 | if (mem[i][x] != -1) return mem[i][x];
582 |
583 | int res = INF;
584 | res = min(res, 1 + opt(i, x - d[i]));
585 | res = min(res, opt(i - 1, x));
586 |
587 | mem[i][x] = res;
588 | return res;
589 | }
590 | \end{minted}
591 | \end{frame}
592 |
593 | \begin{frame}{Coin change}
594 | \vspace{30pt}
595 | \bi
596 | \item Time complexity?
597 | \item Number of possible inputs are $n \times x$
598 | \item Each input will be processed in $O(1)$ time, assuming recursive calls are constant
599 | \item Total time complexity is $O(n\times x)$
600 | \ei
601 | \end{frame}
602 |
603 | \begin{frame}{Coin change}
604 | \bi
605 | \vspace{30pt}
606 | \item How do we know which coins the optimal solution used?
607 | \item We can store backpointers, or some extra information, to trace backwards through the states
608 | \item See example...
609 | \ei
610 | \end{frame}
611 |
612 | \begin{frame}{Longest increasing subsequence}
613 | \bi
614 | \item Given an array $a[0]$, $a[1]$, \ldots, $a[n-1]$ of integers, what is the length of the longest increasing subsequence?
615 | \vspace{15pt}
616 | \item First, what is a subsequence?
617 | \item If we delete zero or more elements from $a$, then we have a subsequence of $a$
618 | \vspace{5pt}
619 | \item Example: $a = [5,1,8,1,9,2]$
620 | \vspace{5pt}
621 | \item $[5,8,9]$ is a subsequence
622 | \item $[1,1]$ is a subsequence
623 | \item $[5,1,8,1,9,2]$ is a subsequence
624 | \item $[]$ is a subsequence
625 | \item $[8,5]$ is \textbf{not} a subsequence
626 | \item $[10]$ is \textbf{not} a subsequence
627 | \ei
628 | \end{frame}
629 |
630 | \begin{frame}{Longest increasing subsequence}
631 | \bi
632 | \item Given an array $a[0]$, $a[1]$, \ldots, $a[n-1]$ of integers, what is the length of the longest increasing subsequence?
633 | \vspace{5pt}
634 | \item An increasing subsequence of $a$ is a subsequence of $a$ such that the elements are in (strictly) increasing order
635 | \vspace{5pt}
636 | \item $[5,8,9]$ and $[1,8,9]$ are the longest increasing subsequences of $a = [5,1,8,1,9,2]$
637 |
638 | \vspace{5pt}
639 | \item How do we compute the length of the longest increasing subsequence?
640 | \item There are $2^n$ subsequences, so we can go through all of them
641 | \item That would result in an $O(n2^n)$ algorithm, which can only handle $n\leq 23$
642 | \vspace{5pt}
643 | \item What about dynamic programming?
644 |
645 | \ei
646 | \end{frame}
647 |
648 | \begin{frame}{Longest increasing subsequence}
649 | \vspace{20pt}
650 | \bi
651 | \item Let $\mathrm{lis}(i)$ denote the length of the longest increasing subsequence of the array $a[0]$, $\ldots$, $a[i]$
652 | \vspace{5pt}
653 | \item Base case: $\mathrm{lis}(0) = 1$
654 | \item What about $\mathrm{lis}(i)$?
655 | \vspace{10pt}
656 | \item We have the same issue as in the maximum sum problem, so let's try changing perspective
657 | \ei
658 | \end{frame}
659 |
660 | \begin{frame}{Longest increasing subsequence}
661 | \vspace{40pt}
662 | \bi
663 | \item Let $\mathrm{lis}(i)$ denote the length of the longest increasing subsequence of the array $a[0]$, $\ldots$, $a[i]$, \textit{that ends at $i$}
664 | \vspace{5pt}
665 | \item Base case: we don't need one
666 | \item $\mathrm{lis}(i) = \mathrm{max}(1, \mathrm{max}_{j 11$
817 |
818 | \vspace{10pt}
819 | \item Can we go higher if we use dynamic programming?
820 | \ei
821 | \end{frame}
822 |
823 | \begin{frame}{Traveling salesman problem}
824 | \vspace{20pt}
825 | \bi
826 | \item Without loss of generality, assume we start and end the cycle at vertex $0$
827 | \vspace{10pt}
828 |
829 | \item Let $\mathrm{tsp}(i, S)$ represent the cheapest way to go through all vertices in the graph and back to vertex $0$, if we're currently at vertex $i$ and we've already visited the vertices in the set $S$
830 |
831 | \vspace{20pt}
832 | \item Base case: $\mathrm{tsp}(i, \textrm{all vertices}) = c_{i,0}$
833 | \item Otherwise $\mathrm{tsp}(i, S) = \mathrm{min}_{\ j \not\in S\ } \{\ c_{i,j} + \mathrm{tsp}(j, S \cup \{j\})\ \}$
834 | \ei
835 | \end{frame}
836 |
837 | \begin{frame}[fragile]{Traveling salesman problem}
838 | \begin{minted}[fontsize=\scriptsize]{cpp}
839 | const int N = 20;
840 | const int INF = 100000000;
841 | int c[N][N];
842 | int mem[N][1<
2 | using namespace std;
3 | typedef long long ll;
4 | typedef pair ii;
5 | typedef vector vi;
6 | typedef vector vii;
7 | template int size(const T &x) { return x.size(); }
8 | // const int INF = 2147483647;
9 | #define rep(i,a,b) for (__typeof(a) i=(a); i<(b); ++i)
10 | #define iter(it,c) for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
11 |
12 |
13 | int INF = 100000;
14 | // int d[10]={1, 10, 21, 34, 70, 100, 350, 1225, 1500};
15 | int d[10]={7,8,9};
16 | int mem[10][10000];
17 | bool take[10][10000];
18 | int opt(int i, int x) {
19 | if (x < 0) return INF;
20 | if (x == 0) return 0;
21 | if (i == -1) return INF;
22 | if (mem[i][x] != -1) return mem[i][x];
23 |
24 | int res = INF,
25 | a = 1 + opt(i, x - d[i]),
26 | b = opt(i - 1, x);
27 |
28 | take[i][x] = true;
29 | res = a;
30 |
31 | if (b < a) {
32 | take[i][x] = false;
33 | res = b;
34 | }
35 |
36 | mem[i][x] = res;
37 | return res;
38 | }
39 |
40 | void reconstruct(int i, int x) {
41 | if (x < 0) {
42 | assert(false);
43 | return;
44 | }
45 | if (x == 0) {
46 | cout << endl;
47 | return;
48 | }
49 | if (i == -1) {
50 | assert(false);
51 | return;
52 | }
53 |
54 | if (take[i][x]) {
55 | cout << d[i] << " ";
56 | reconstruct(i, x - d[i]);
57 | } else {
58 | reconstruct(i - 1, x);
59 | }
60 | }
61 |
62 | int main() {
63 | memset(mem, -1, sizeof(mem));
64 |
65 | int x = 5;
66 | cout << opt(2, x) << endl;
67 | if (opt(2, x) == INF) {
68 | cout << "impossible" << endl;
69 | } else {
70 | reconstruct(2, x);
71 | }
72 |
73 | return 0;
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/06_dynamic_programming/coin_change_expl.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include