├── 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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | typedef long long ll; 26 | typedef pair ii; 27 | typedef vector vi; 28 | typedef vector vii; 29 | typedef vector vvi; 30 | typedef vector vvii; 31 | template int size(T &x) { return x.size(); } 32 | 33 | // assert or gtfo 34 | 35 | 36 | int INF = 100000; // INF táknar óendanlegt, nota það til að segja ef það er ekki til lausn 37 | int d[10]; // d[i] er gildið á peningi i 38 | int mem[10][10000]; // mem[i][x] er svarið við opt(i, x), eða -1 ef við vitum ekki hvað svarið er. 39 | // mem fylkið er notað svo við séum ekki að endurreikna svarið við opt(i, x) oft. 40 | // þetta er það sem gerir forritið hratt, og er kallað memoization (sem er ein leið til að leysa vandamál með dynamic programming) 41 | bool taken[10][10000]; // taken[i][x] segir hvort við tókum i-ta peninginn eða ekki í optimal lausninni sem við finnum í opt(i, x), sjá betur að neðan 42 | 43 | int opt(int i, int x) { 44 | if (x < 0) return INF; 45 | if (x == 0) return 0; 46 | if (i == -1) return INF; 47 | 48 | if (mem[i][x] != -1) return mem[i][x]; 49 | 50 | int res = INF; 51 | 52 | int a = 1 + opt(i, x - d[i]); 53 | int b = opt(i - 1, x); 54 | 55 | if (a < b) { 56 | taken[i][x] = true; 57 | } else { 58 | taken[i][x] = false; 59 | } 60 | 61 | res = min(a, b); 62 | 63 | mem[i][x] = res; 64 | return res; 65 | } 66 | 67 | 68 | void find_opt(int i, int x) { 69 | if (x == 0) { 70 | return; 71 | } 72 | 73 | if (taken[i][x]) { 74 | cout << d[i] << " "; 75 | 76 | find_opt(i, x - d[i]); 77 | 78 | } else { 79 | 80 | find_opt(i - 1, x); 81 | } 82 | } 83 | 84 | 85 | int main() 86 | { 87 | memset(mem, -1, sizeof(mem)); 88 | 89 | int dcnt = 3; 90 | 91 | d[0] = 7; 92 | d[1] = 8; 93 | d[2] = 9; 94 | 95 | for (int x = 0; x <= 100; x++) { 96 | cout << x << " " << opt(dcnt - 1, x) << ": "; 97 | 98 | if (opt(dcnt - 1, x) == INF) { 99 | cout << "IMPOSSIBLE" << endl; 100 | } else { 101 | find_opt(dcnt - 1, x); 102 | cout << endl; 103 | } 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /06_dynamic_programming/fibonacci2.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 | ll memory[1000]; 13 | ll fibonacci(int n) { 14 | if (n <= 2) { 15 | return 1; 16 | } 17 | if (memory[n] != -1) { 18 | return memory[n]; 19 | } 20 | ll res = fibonacci(n-2) + fibonacci(n-1); 21 | memory[n] = res; 22 | return res; 23 | } 24 | 25 | int main() { 26 | memset(memory, -1, sizeof(memory)); 27 | cout << fibonacci(500) << endl; 28 | 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /06_dynamic_programming/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/06_dynamic_programming/kattis.png -------------------------------------------------------------------------------- /06_dynamic_programming/lcs_2.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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | const int INF = 2147483647; 26 | typedef long long ll; 27 | typedef pair ii; 28 | typedef vector vi; 29 | typedef vector vii; 30 | typedef vector vvi; 31 | typedef vector vvii; 32 | template int size(T &x) { return x.size(); } 33 | 34 | // assert or gtfo 35 | 36 | string a = "bananinn"; 37 | string b = "kaninan"; 38 | 39 | int lcs(int i, int j) { 40 | if (i == -1 || j == -1) { 41 | return 0; 42 | } 43 | 44 | int res = 0; 45 | res = max(res, lcs(i - 1, j)); 46 | res = max(res, lcs(i, j - 1)); 47 | if (a[i] == b[j]) { 48 | res = max(res, 1 + lcs(i - 1, j - 1)); 49 | } 50 | 51 | return res; 52 | } 53 | 54 | int main() { 55 | 56 | cout << lcs(a.size() - 1, b.size() - 1) << endl; 57 | 58 | return 0; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /06_dynamic_programming/lis_2.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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | const int INF = 2147483647; 26 | typedef long long ll; 27 | typedef pair ii; 28 | typedef vector vi; 29 | typedef vector vii; 30 | typedef vector vvi; 31 | typedef vector vvii; 32 | template int size(T &x) { return x.size(); } 33 | 34 | // assert or gtfo 35 | 36 | int a[1000]; 37 | int mem[1000]; 38 | 39 | int lis(int i) { 40 | if (mem[i] != -1) { 41 | return mem[i]; 42 | } 43 | 44 | int res = 1; 45 | for (int j = 0; j < i; j++) { 46 | if (a[j] < a[i]) { 47 | res = max(res, 1 + lis(j)); 48 | } 49 | } 50 | 51 | mem[i] = res; 52 | return res; 53 | } 54 | 55 | int main() 56 | { 57 | memset(mem, -1, sizeof(mem)); 58 | a[0] = 5; 59 | a[1] = 1; 60 | a[2] = 8; 61 | a[3] = 1; 62 | a[4] = 9; 63 | a[5] = 2; 64 | 65 | for (int i = 0; i < 6; i++) { 66 | cout << a[i] << ": " << lis(i) << endl; 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /07_graphs_1/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 7: Unweighted graphs 2 | 3 | Reviews basic graph theory. Covers depth-first search, breadth-first search, and applications. 4 | 5 |

Problems

6 | Solve some of the following problems on Kattis. You need 4 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 | -------------------------------------------------------------------------------- /07_graphs_1/aflv_07_graphs_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/07_graphs_1/aflv_07_graphs_1.pdf -------------------------------------------------------------------------------- /07_graphs_1/bfs.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 | vector adj[1000]; 13 | vector dist(1000, -1); 14 | int back[1000]; 15 | 16 | int main() { 17 | 18 | int A = 0, 19 | B = 1; 20 | 21 | adj[0].push_back(1); 22 | adj[1].push_back(0); 23 | 24 | queue Q; 25 | Q.push(A); 26 | dist[A] = 0; 27 | back[A] = -1; 28 | 29 | while (!Q.empty()) { 30 | int u = Q.front(); Q.pop(); 31 | 32 | for (int i = 0; i < adj[u].size(); i++) { 33 | int v = adj[u][i]; 34 | if (dist[v] == -1) { 35 | Q.push(v); 36 | dist[v] = 1 + dist[u]; 37 | back[v] = u; 38 | } 39 | } 40 | } 41 | 42 | printf("dist: %d\n", dist[B]); 43 | printf("path (reversed):\n"); 44 | 45 | int cur = B; 46 | while (true) { 47 | printf("%d\n", cur); 48 | if (back[cur] == -1) { 49 | break; 50 | } 51 | cur = back[cur]; 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /07_graphs_1/bridges_2.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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | const int INF = 2147483647; 26 | typedef long long ll; 27 | typedef pair ii; 28 | typedef vector vi; 29 | typedef vector vii; 30 | typedef vector vvi; 31 | typedef vector vvii; 32 | template int size(T &x) { return x.size(); } 33 | 34 | // assert or gtfo 35 | 36 | const int n = 6; 37 | vector adj[n]; 38 | vector low(n), num(n, -1); 39 | int curnum = 0; 40 | 41 | vector > bridges; 42 | 43 | void find_bridges(int u, int p) { 44 | low[u] = num[u] = curnum++; 45 | for (int i = 0; i < adj[u].size(); i++) { 46 | int v = adj[u][i]; 47 | if (v == p) continue; 48 | if (num[v] == -1) { 49 | find_bridges(v, u); 50 | low[u] = min(low[u], low[v]); 51 | } else { 52 | low[u] = min(low[u], num[v]); 53 | } 54 | 55 | if (low[v] > num[u]) { 56 | bridges.push_back(make_pair(u, v)); 57 | } 58 | } 59 | } 60 | 61 | 62 | int main() { 63 | 64 | adj[0].push_back(1); 65 | adj[0].push_back(2); 66 | adj[1].push_back(0); 67 | adj[1].push_back(2); 68 | adj[2].push_back(0); 69 | adj[2].push_back(1); 70 | adj[2].push_back(3); 71 | adj[3].push_back(2); 72 | adj[3].push_back(4); 73 | adj[3].push_back(5); 74 | adj[4].push_back(3); 75 | adj[4].push_back(5); 76 | adj[5].push_back(3); 77 | adj[5].push_back(4); 78 | 79 | for (int u = 0; u < n; u++) { 80 | if (num[u] == -1) { 81 | find_bridges(u, -1); 82 | } 83 | } 84 | 85 | for (int i = 0; i < bridges.size(); i++) { 86 | printf("%d %d\n", bridges[i].first, bridges[i].second); 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /07_graphs_1/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/07_graphs_1/kattis.png -------------------------------------------------------------------------------- /07_graphs_1/tourist.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 | vector adj[100]; 14 | vector low(100), num(100, -1); 15 | vector incomp(100, false); 16 | 17 | int curnum = 0; 18 | stack comp; 19 | 20 | int num_comps = 0; 21 | int num_comp[1000]; 22 | vector C[1000]; 23 | void scc(int u) { 24 | comp.push(u); 25 | incomp[u] = true; 26 | low[u] = num[u] = curnum++; 27 | for (int i = 0; i < adj[u].size(); i++) { 28 | int v = adj[u][i]; 29 | if (num[v] == -1) { 30 | scc(v); 31 | low[u] = min(low[u], low[v]); 32 | } else if (incomp[v]) { 33 | low[u] = min(low[u], num[v]); 34 | } 35 | } 36 | if (num[u] == low[u]) { 37 | while (true) { 38 | int cur = comp.top(); 39 | comp.pop(); 40 | 41 | num_comp[cur] = num_comps; 42 | C[num_comps].push_back(cur); 43 | 44 | incomp[cur] = false; 45 | if (cur == u) { 46 | break; 47 | } 48 | } 49 | 50 | num_comps++; 51 | } 52 | } 53 | 54 | int main() { 55 | int n, m; 56 | cin >> n >> m; 57 | for (int i = 0; i < m; i++) { 58 | int a, b; 59 | cin >> a >> b; 60 | adj[a].push_back(b); 61 | } 62 | 63 | for (int i = 0; i < n; i++) { 64 | if (num[i] == -1) { 65 | scc(i); 66 | } 67 | } 68 | 69 | for (int i = 0; i < num_comps; i++) { 70 | bool ok = true; 71 | for (int j = 0; j < C[i].size(); j++) { 72 | int u = C[i][j]; 73 | for (int k = 0; k < adj[u].size(); k++) { 74 | int v = adj[u][k]; 75 | if (num_comp[u] != num_comp[v]) { 76 | ok = false; 77 | } 78 | } 79 | } 80 | if (ok) { 81 | for (int j = 0; j < C[i].size(); j++) { 82 | int u = C[i][j]; 83 | printf("%d\n", u); 84 | } 85 | } 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /08_graphs_2/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 8: Graphs 2 | 3 | Covers minimum spanning trees, shortest paths, some graph theory, and some special types of graphs. 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 | -------------------------------------------------------------------------------- /08_graphs_2/aflv_08_graphs_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/08_graphs_2/aflv_08_graphs_2.pdf -------------------------------------------------------------------------------- /08_graphs_2/aflv_08_graphs_2.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{Graphs} 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{selected2 vertex} = [vertex, fill=hilight!50, text=black] 43 | \tikzstyle{ignored edge} = [draw,line width=5pt,-,black!20] 44 | \tikzstyle{vertex1} = [vertex, fill=red] 45 | \tikzstyle{vertex2} = [vertex, fill=blue] 46 | \tikzstyle{vertex3} = [vertex, fill=green, text=black] 47 | \tikzstyle{vertex4} = [vertex, fill=yellow, text=black] 48 | \tikzstyle{vertex5} = [vertex, fill=pink, text=black] 49 | \tikzstyle{vertex6} = [vertex, fill=purple] 50 | 51 | \tikzset{ 52 | treenode/.style = {align=center, inner sep=0pt, text centered, 53 | font=\sffamily}, 54 | vertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=black, text width=1.8em},% arbre rouge noir, noeud noir 55 | rvertex/.style = {treenode, circle, black, font=\sffamily\bfseries\tiny, draw=red, text width=1.8em},% arbre rouge noir, noeud noir 56 | } 57 | 58 | \begin{document} 59 | \maketitle 60 | 61 | \begin{frame}{Today we're going to cover} 62 | \bi 63 | \item Minimum spanning tree 64 | \item Shortest paths 65 | % \item Transitive closure 66 | % \item Minimax/maximin 67 | \item Some known graph problems 68 | \item Special graphs 69 | \bi 70 | \item Trees 71 | \item Directed acyclic graphs 72 | \item Bipartite graphs 73 | \ei 74 | 75 | % - Minimum spanning tree (and variants) 76 | % - Shortest path (Dijkstra, Bellman-Ford, Floyd-Warshall) 77 | % - Transitive closure 78 | % - Minimax and maximin 79 | % - Special graphs 80 | % - Trees 81 | % - DAGs 82 | % - Bipartite graphs 83 | \ei 84 | \end{frame} 85 | 86 | % TODO: ... 87 | 88 | \begin{frame}{Weighted graphs} 89 | \bi 90 | \item Now the edges in our graphs may have weights, which could represent 91 | \bi 92 | \item the distance of the road represented by the edge 93 | \item the cost of going over the edge 94 | \item some capacity of the edge 95 | \ei 96 | 97 | \item We can use a modified adjacency list to represent weighted graphs 98 | \ei 99 | \end{frame} 100 | 101 | \begin{frame}[fragile]{Weighted graphs} 102 | \begin{columns}[T] 103 | \begin{column}{.4\textwidth} 104 | \begin{minted}[fontsize=\footnotesize]{cpp} 105 | struct edge { 106 | int u, v; 107 | int weight; 108 | 109 | edge(int _u, int _v, int _w) { 110 | u = _u; 111 | v = _v; 112 | weight = _w; 113 | } 114 | }; 115 | \end{minted} 116 | \end{column}% 117 | \hfill% 118 | \begin{column}{.6\textwidth} 119 | \begin{figure} 120 | \begin{tikzpicture}[scale=1.8,auto,swap] 121 | \node[vertex] (0) at (0.5,3) {0}; 122 | \node[vertex] (1) at (0,2) {1}; 123 | \node[vertex] (2) at (1,2) {2}; 124 | \node[vertex] (3) at (0.5,1) {3}; 125 | 126 | \path[edge] (0) -- node[weight,left] {3} (1); 127 | \path[edge] (0) -- node[weight,right] {-4} (2); 128 | \path[edge] (1) -- node[weight,above] {0} (2); 129 | \path[edge] (2) -- node[weight,right,pos=0.6] {2.9} (3); 130 | 131 | \pgfresetboundingbox 132 | \path [use as bounding box] (0,0) rectangle (1,3.2); 133 | \end{tikzpicture} 134 | \end{figure} 135 | \end{column}% 136 | \end{columns} 137 | \end{frame} 138 | 139 | \begin{frame}[fragile]{Weighted graphs} 140 | \begin{columns}[T] 141 | \begin{column}{.4\textwidth} 142 | \begin{minted}[fontsize=\footnotesize]{cpp} 143 | vector adj[4]; 144 | 145 | adj[0].push_back(edge(0, 1, 3)); 146 | adj[0].push_back(edge(0, 2, -4)); 147 | 148 | adj[1].push_back(edge(1, 0, 3)); 149 | adj[1].push_back(edge(1, 2, 0)); 150 | 151 | adj[2].push_back(edge(2, 0, -4)); 152 | adj[2].push_back(edge(2, 1, 0)); 153 | adj[2].push_back(edge(2, 3, 2.9)); 154 | 155 | adj[3].push_back(edge(3, 2, 2.9)); 156 | 157 | \end{minted} 158 | \end{column}% 159 | \hfill% 160 | \begin{column}{.6\textwidth} 161 | \begin{figure} 162 | \begin{tikzpicture}[scale=1.8,auto,swap] 163 | \node[vertex] (0) at (0.5,3) {0}; 164 | \node[vertex] (1) at (0,2) {1}; 165 | \node[vertex] (2) at (1,2) {2}; 166 | \node[vertex] (3) at (0.5,1) {3}; 167 | 168 | \path[edge] (0) -- node[weight,left] {3} (1); 169 | \path[edge] (0) -- node[weight,right] {-4} (2); 170 | \path[edge] (1) -- node[weight,above] {0} (2); 171 | \path[edge] (2) -- node[weight,right,pos=0.6] {2.9} (3); 172 | 173 | \pgfresetboundingbox 174 | \path [use as bounding box] (0,0) rectangle (1,3.2); 175 | \end{tikzpicture} 176 | \end{figure} 177 | \end{column}% 178 | \end{columns} 179 | \end{frame} 180 | 181 | \begin{frame}{Minimum spanning tree} 182 | \bi 183 | \item We have an undirected weighted graph 184 | \item The vertices along with a subset of the edges in the graph is called a spanning tree if 185 | \bi 186 | \item it forms a tree (i.e.\ does not contain a cycle) and 187 | \item the tree spans all vertices (all vertices can reach all other vertices) 188 | \ei 189 | \vspace{10pt} 190 | \item The weight of a spanning tree is the sum of the weights of the edges in the subset 191 | \vspace{10pt} 192 | \item We want to find a minimum spannig tree 193 | \ei 194 | \end{frame} 195 | 196 | \begin{frame}{Minimum spanning tree} 197 | \bi 198 | \item Several greedy algorithms work 199 | \vspace{10pt} 200 | \item Go through the edges in the graph in increasing order of weight 201 | \item Greedily pick an edge if it doesn't form a cycle (Union-Find can be used to keep track of when we would get a cycle) 202 | \item When we've gone through all edges, we have a minimum spanning tree 203 | \vspace{10pt} 204 | \item This is Kruskal's algorithm 205 | \item Time complexity is $O(E \log E)$ 206 | \ei 207 | \end{frame} 208 | 209 | \begin{frame}[fragile]{Minimum spanning tree} 210 | \begin{minted}[fontsize=\scriptsize]{cpp} 211 | 212 | bool edge_cmp(const edge &a, const edge &b) { 213 | return a.weight < b.weight; 214 | } 215 | 216 | vector mst(int n, vector edges) { 217 | union_find uf(n); 218 | sort(edges.begin(), edges.end(), edge_cmp); 219 | 220 | vector res; 221 | for (int i = 0; i < edges.size(); i++) { 222 | int u = edges[i].u, 223 | v = edges[i].v; 224 | 225 | if (uf.find(u) != uf.find(v)) { 226 | uf.unite(u, v); 227 | res.push_back(edges[i]); 228 | } 229 | } 230 | 231 | return res; 232 | } 233 | \end{minted} 234 | \end{frame} 235 | 236 | % TODO: Example problem: 237 | % \begin{frame}{Example problem: Dark roads} 238 | % \bi 239 | % \item http://uva.onlinejudge.org/external/116/11631.html 240 | % \ei 241 | % \end{frame} 242 | 243 | \begin{frame}{Shortest paths} 244 | \bi 245 | \item We have a weighted graph (undirected or directed) 246 | \item Given two vertices $u,v$, what is the shortest path from $u$ to $v$? 247 | \vspace{10pt} 248 | \item If all weights are the same, this can be solved with breadth-first search 249 | \item Of course, this is usually not the case... 250 | \ei 251 | \end{frame} 252 | 253 | \begin{frame}{Shortest paths} 254 | \bi 255 | \item There are many known algorithms to find shortest paths 256 | \item Like breadth-first search, these algorithms usually find the shortest paths from a given start vertex to all other vertices 257 | \vspace{5pt} 258 | \item Let's take a quick look at Dijkstra's algorithm, the Bellman-Ford algorithm and the Floyd-Warshall algorithm 259 | \ei 260 | \end{frame} 261 | 262 | % TODO: Dijkstra's algorithm 263 | % \begin{frame}{Dijkstra's algorithm} 264 | % \bi 265 | % \item 266 | % \ei 267 | % \end{frame} 268 | 269 | \begin{frame}[fragile]{Dijkstra's algorithm} 270 | \begin{minted}[fontsize=\scriptsize]{cpp} 271 | vector adj[100]; 272 | vector dist(100, INF); 273 | 274 | void dijkstra(int start) { 275 | dist[start] = 0; 276 | priority_queue, 277 | vector >, 278 | greater > > pq; 279 | pq.push(make_pair(dist[start], start)); 280 | 281 | while (!pq.empty()) { 282 | int u = pq.top().second; 283 | pq.pop(); 284 | 285 | for (int i = 0; i < adj[u].size(); i++) { 286 | int v = adj[u][i].v; 287 | int w = adj[u][i].weight; 288 | 289 | if (w + dist[u] < dist[v]) { 290 | dist[v] = w + dist[u]; 291 | pq.push(make_pair(dist[v], v)); 292 | } 293 | } 294 | } 295 | } 296 | \end{minted} 297 | \end{frame} 298 | 299 | \begin{frame}{Dijkstra's algorithm} 300 | \bi 301 | \item Time complexity is $O(V \log E)$ 302 | \vspace{10pt} 303 | \item Note that this only works for non-negative weights 304 | \ei 305 | \end{frame} 306 | 307 | % TODO: Bellman-Ford algorithm 308 | \begin{frame}[fragile]{Bellman-Ford algorithm} 309 | \begin{minted}[fontsize=\footnotesize]{cpp} 310 | void bellman_ford(int n, int start) { 311 | 312 | dist[start] = 0; 313 | 314 | for (int i = 0; i < n - 1; i++) { 315 | for (int u = 0; u < n; u++) { 316 | for (int j = 0; j < adj[u].size(); j++) { 317 | int v = adj[u][j].v; 318 | int w = adj[u][j].weight; 319 | dist[v] = min(dist[v], w + dist[u]); 320 | } 321 | } 322 | } 323 | } 324 | \end{minted} 325 | \end{frame} 326 | 327 | \begin{frame}{Bellman-Ford algorithm} 328 | \bi 329 | \item Time complexity is $O(V\times E)$ 330 | \vspace{10pt} 331 | \item Can be used to detect negative-weight cycles 332 | \ei 333 | \end{frame} 334 | 335 | % TODO: Floyd-Warshall algorithm 336 | \begin{frame}{Floyd-Warshall algorithm} 337 | \bi 338 | \item What about using dynamic programming to compute shortest paths? 339 | \vspace{10pt} 340 | \item Let $\mathrm{sp}(k, i, j)$ be the shortest path from $i$ to $j$ if we're only allowed to travel through the vertices $0$, \ldots, $k$ 341 | \vspace{5pt} 342 | \item Base case: $\mathrm{sp}(k, i, j) = 0$ if $i = j$ 343 | \item Base case: $\mathrm{sp}(-1, i, j) = \mathrm{weight}[a][b]$ if $(i,j) \in E$ 344 | \item Base case: $\mathrm{sp}(-1, i, j) = \infty$ 345 | \vspace{5pt} 346 | \item $\mathrm{sp}(k, i, j) = \mathrm{min} \left\{ 347 | \begin{array}{l} 348 | \mathrm{sp}(k - 1, i, k) + \mathrm{sp}(k - 1, k, j) \\ 349 | \mathrm{sp}(k - 1, i, j) 350 | \end{array} 351 | \right.$ 352 | \ei 353 | \end{frame} 354 | 355 | \begin{frame}[fragile]{Floyd-Warshall algorithm} 356 | \begin{minted}[fontsize=\scriptsize]{cpp} 357 | int dist[1000][1000]; 358 | int weight[1000][1000]; 359 | 360 | void floyd_warshall(int n) { 361 | for (int i = 0; i < n; i++) { 362 | for (int j = 0; j < n; j++) { 363 | dist[i][j] = i == j ? 0 : weight[i][j]; 364 | } 365 | } 366 | 367 | for (int k = 0; k < n; k++) { 368 | for (int i = 0; i < n; i++) { 369 | for (int j = 0; j < n; j++) { 370 | dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 371 | } 372 | } 373 | } 374 | } 375 | \end{minted} 376 | \end{frame} 377 | 378 | \begin{frame}{Floyd-Warshall algorithm} 379 | \bi 380 | \item Computes all-pairs shortest paths 381 | \item Time complexity is clearly $O(n^3)$ 382 | \item Very simple to code 383 | \ei 384 | \end{frame} 385 | 386 | % \begin{frame}{Transitive closure} 387 | % \end{frame} 388 | % 389 | % \begin{frame}{Minimax/maximin} 390 | % \end{frame} 391 | 392 | % TODO: Some common graph problems 393 | \begin{frame}{Known graph problems} 394 | \bi 395 | \item The problems we're dealing with very often ask us to solve some well known graph problem 396 | \item But usually it's well hidden in the problem statement 397 | \vspace{10pt} 398 | \item Let's take a look at a few examples 399 | \ei 400 | \end{frame} 401 | 402 | % TODO: Minimum vertex cover 403 | \begin{frame}{Minimum vertex cover} 404 | \bi 405 | \item We have an unweighted undirected graph 406 | \item A vertex cover is a subset of the vertices $S$, such that for each edge $(u, v)$ in the graph, either $u$ or $v$ (or both) are in $S$ 407 | \ei 408 | 409 | \begin{figure} 410 | \begin{tikzpicture}[scale=1.8,auto,swap] 411 | \onslide<1>{ 412 | \node[vertex] (0) at (0,0.5) {0}; 413 | \node[vertex] (1) at (0.8,1) {1}; 414 | \node[vertex] (2) at (0.8,0) {2}; 415 | \node[vertex] (3) at (2,1) {3}; 416 | \node[vertex] (4) at (1.8,0.5) {4}; 417 | \node[vertex] (5) at (1.6,0) {5}; 418 | } 419 | \onslide<2-3>{ 420 | \node[selected vertex] (0) at (0,0.5) {0}; 421 | \node[selected vertex] (1) at (0.8,1) {1}; 422 | \node[vertex] (2) at (0.8,0) {2}; 423 | \node[vertex] (3) at (2,1) {3}; 424 | \node[selected vertex] (4) at (1.8,0.5) {4}; 425 | \node[vertex] (5) at (1.6,0) {5}; 426 | } 427 | \onslide<4->{ 428 | \node[vertex] (0) at (0,0.5) {0}; 429 | \node[selected vertex] (1) at (0.8,1) {1}; 430 | \node[selected vertex] (2) at (0.8,0) {2}; 431 | \node[vertex] (3) at (2,1) {3}; 432 | \node[vertex] (4) at (1.8,0.5) {4}; 433 | \node[vertex] (5) at (1.6,0) {5}; 434 | } 435 | 436 | \path[edge] (0) -- (1); 437 | \path[edge] (0) -- (2); 438 | \path[edge] (1) -- (2); 439 | \path[edge] (1) -- (3); 440 | \path[edge] (1) -- (4); 441 | \path[edge] (1) -- (5); 442 | 443 | \pgfresetboundingbox 444 | \path [use as bounding box] (0.8,0) rectangle (1,1.2); 445 | \end{tikzpicture} 446 | \end{figure} 447 | 448 | \vspace{10pt} 449 | \bi 450 | \item<3-> We want to find a vertex cover of minimum size 451 | \vspace{10pt} 452 | \item<5-> NP-hard problem in general graphs 453 | \ei 454 | \end{frame} 455 | 456 | % TODO: Maximum independent set 457 | \begin{frame}{Maximum independent set} 458 | \bi 459 | \item We have an unweighted undirected graph 460 | \item An independent set is a subset of the vertices $S$, such that no two vertices $u,v$ in $S$ are adjacent in the graph 461 | \ei 462 | 463 | \begin{figure} 464 | \begin{tikzpicture}[scale=1.8,auto,swap] 465 | \onslide<1>{ 466 | \node[vertex] (0) at (0,0.5) {0}; 467 | \node[vertex] (1) at (0.8,1) {1}; 468 | \node[vertex] (2) at (0.8,0) {2}; 469 | \node[vertex] (3) at (2,1) {3}; 470 | \node[vertex] (4) at (1.8,0.5) {4}; 471 | \node[vertex] (5) at (1.6,0) {5}; 472 | } 473 | \onslide<2-3>{ 474 | \node[vertex] (0) at (0,0.5) {0}; 475 | \node[vertex] (1) at (0.8,1) {1}; 476 | \node[selected vertex] (2) at (0.8,0) {2}; 477 | \node[selected vertex] (3) at (2,1) {3}; 478 | \node[vertex] (4) at (1.8,0.5) {4}; 479 | \node[selected vertex] (5) at (1.6,0) {5}; 480 | } 481 | \onslide<4->{ 482 | \node[selected vertex] (0) at (0,0.5) {0}; 483 | \node[vertex] (1) at (0.8,1) {1}; 484 | \node[vertex] (2) at (0.8,0) {2}; 485 | \node[selected vertex] (3) at (2,1) {3}; 486 | \node[selected vertex] (4) at (1.8,0.5) {4}; 487 | \node[selected vertex] (5) at (1.6,0) {5}; 488 | } 489 | 490 | \path[edge] (0) -- (1); 491 | \path[edge] (0) -- (2); 492 | \path[edge] (1) -- (2); 493 | \path[edge] (1) -- (3); 494 | \path[edge] (1) -- (4); 495 | \path[edge] (1) -- (5); 496 | 497 | \pgfresetboundingbox 498 | \path [use as bounding box] (0.8,0) rectangle (1,1.2); 499 | \end{tikzpicture} 500 | \end{figure} 501 | 502 | \vspace{10pt} 503 | \bi 504 | \item<3-> We want to find an independent set of maximum size 505 | \vspace{10pt} 506 | \item<5-> NP-hard problem in general graphs 507 | \ei 508 | \end{frame} 509 | 510 | \begin{frame}{Relation between MVC and MIS} 511 | \bi 512 | \item The previous two problems are very related 513 | \item A subset of the vertices is a vertex cover if and only if the complement of the set is an independent set 514 | \ei 515 | 516 | \begin{figure} 517 | \begin{tikzpicture}[scale=1.8,auto,swap] 518 | \onslide<1>{ 519 | \node[vertex] (0) at (0,0.5) {0}; 520 | \node[vertex] (1) at (0.8,1) {1}; 521 | \node[vertex] (2) at (0.8,0) {2}; 522 | \node[vertex] (3) at (2,1) {3}; 523 | \node[vertex] (4) at (1.8,0.5) {4}; 524 | \node[vertex] (5) at (1.6,0) {5}; 525 | } 526 | \onslide<2>{ 527 | \node[selected2 vertex] (0) at (0,0.5) {0}; 528 | \node[selected2 vertex] (1) at (0.8,1) {1}; 529 | \node[selected vertex] (2) at (0.8,0) {2}; 530 | \node[selected vertex] (3) at (2,1) {3}; 531 | \node[selected2 vertex] (4) at (1.8,0.5) {4}; 532 | \node[selected vertex] (5) at (1.6,0) {5}; 533 | } 534 | \onslide<3->{ 535 | \node[selected vertex] (0) at (0,0.5) {0}; 536 | \node[selected2 vertex] (1) at (0.8,1) {1}; 537 | \node[selected2 vertex] (2) at (0.8,0) {2}; 538 | \node[selected vertex] (3) at (2,1) {3}; 539 | \node[selected vertex] (4) at (1.8,0.5) {4}; 540 | \node[selected vertex] (5) at (1.6,0) {5}; 541 | } 542 | 543 | \path[edge] (0) -- (1); 544 | \path[edge] (0) -- (2); 545 | \path[edge] (1) -- (2); 546 | \path[edge] (1) -- (3); 547 | \path[edge] (1) -- (4); 548 | \path[edge] (1) -- (5); 549 | 550 | \pgfresetboundingbox 551 | \path [use as bounding box] (0.8,0) rectangle (1,1.2); 552 | \end{tikzpicture} 553 | \end{figure} 554 | 555 | \vspace{10pt} 556 | \bi 557 | \item<4-> The size of a minimum vertex cover plus the size of a maximum independent set is equal to the number of vertices 558 | \ei 559 | \end{frame} 560 | 561 | % TODO: Matching 562 | \begin{frame}{Maximum matching} 563 | \bi 564 | \item We have an unweighted undirected graph 565 | \item A matching is a subset of the edges such that each vertex is adjacent to at most one edge in the subset 566 | \ei 567 | 568 | \begin{figure} 569 | \begin{tikzpicture}[scale=1.8,auto,swap] 570 | \node[vertex] (0) at (0,0.5) {0}; 571 | \node[vertex] (1) at (0.8,1) {1}; 572 | \node[vertex] (2) at (0.8,0) {2}; 573 | \node[vertex] (3) at (2,1) {3}; 574 | \node[vertex] (4) at (1.8,0.5) {4}; 575 | \node[vertex] (5) at (1.6,0) {5}; 576 | \node[vertex] (6) at (2.4,0) {6}; 577 | 578 | \onslide<1>{ 579 | \path[edge] (0) -- (1); 580 | \path[edge] (0) -- (2); 581 | \path[edge] (1) -- (2); 582 | \path[edge] (1) -- (3); 583 | \path[edge] (1) -- (4); 584 | \path[edge] (1) -- (5); 585 | \path[edge] (5) -- (6); 586 | } 587 | \onslide<2-3>{ 588 | \path[selected edge] (0) -- (1); 589 | \path[edge] (0) -- (2); 590 | \path[edge] (1) -- (2); 591 | \path[edge] (1) -- (3); 592 | \path[edge] (1) -- (4); 593 | \path[edge] (1) -- (5); 594 | \path[selected edge] (5) -- (6); 595 | } 596 | \onslide<4->{ 597 | \path[edge] (0) -- (1); 598 | \path[selected edge] (0) -- (2); 599 | \path[edge] (1) -- (2); 600 | \path[selected edge] (1) -- (3); 601 | \path[edge] (1) -- (4); 602 | \path[edge] (1) -- (5); 603 | \path[selected edge] (5) -- (6); 604 | } 605 | 606 | \pgfresetboundingbox 607 | \path [use as bounding box] (1.5,0) rectangle (1,1.2); 608 | \end{tikzpicture} 609 | \end{figure} 610 | 611 | \vspace{10pt} 612 | \bi 613 | \item<3-> We want to find a matching of maximum size 614 | \vspace{10pt} 615 | \item<5-> There exists an $O(V^4)$ algorithm for general graphs, but is pretty complex 616 | \ei 617 | \end{frame} 618 | 619 | % TODO: Coloring 620 | \begin{frame}{Graph coloring} 621 | \bi 622 | \item We have an unweighted undirected graph 623 | \item A coloring of the graph is an assignment of colors to the vertices such that adjacent vertices have different colors 624 | \ei 625 | 626 | \begin{figure} 627 | \begin{tikzpicture}[scale=1.8,auto,swap] 628 | \onslide<1>{ 629 | \node[vertex] (0) at (0,0.5) {0}; 630 | \node[vertex] (1) at (0.8,1) {1}; 631 | \node[vertex] (2) at (0.8,0) {2}; 632 | \node[vertex] (3) at (2,1) {3}; 633 | \node[vertex] (4) at (1.8,0.5) {4}; 634 | \node[vertex] (5) at (1.6,0) {5}; 635 | } 636 | \onslide<2-3>{ 637 | \node[vertex1] (0) at (0,0.5) {0}; 638 | \node[vertex2] (1) at (0.8,1) {1}; 639 | \node[vertex3] (2) at (0.8,0) {2}; 640 | \node[vertex4] (3) at (2,1) {3}; 641 | \node[vertex5] (4) at (1.8,0.5) {4}; 642 | \node[vertex6] (5) at (1.6,0) {5}; 643 | } 644 | \onslide<4->{ 645 | \node[vertex1] (0) at (0,0.5) {0}; 646 | \node[vertex2] (1) at (0.8,1) {1}; 647 | \node[vertex3] (2) at (0.8,0) {2}; 648 | \node[vertex1] (3) at (2,1) {3}; 649 | \node[vertex1] (4) at (1.8,0.5) {4}; 650 | \node[vertex1] (5) at (1.6,0) {5}; 651 | } 652 | 653 | \path[edge] (0) -- (1); 654 | \path[edge] (0) -- (2); 655 | \path[edge] (1) -- (2); 656 | \path[edge] (1) -- (3); 657 | \path[edge] (1) -- (4); 658 | \path[edge] (1) -- (5); 659 | 660 | \pgfresetboundingbox 661 | \path [use as bounding box] (1.5,0) rectangle (1,1.2); 662 | \end{tikzpicture} 663 | \end{figure} 664 | 665 | \vspace{10pt} 666 | \bi 667 | \item<3-> We want to find a coloring that uses the minimum number of distinct colors 668 | \vspace{10pt} 669 | \item<5-> NP-hard in general graphs 670 | \ei 671 | 672 | \end{frame} 673 | 674 | \begin{frame}{Special graphs} 675 | \bi 676 | \item All of these problems are hard (in some sense) in general graphs 677 | \item But what if we're working with special kinds of graphs? 678 | \vspace{10pt} 679 | \item Let's look at a few examples 680 | \ei 681 | \end{frame} 682 | 683 | \begin{frame}{Bipartite graphs} 684 | \bi 685 | \item A graph is bipartite if the vertices can be partitioned into two sets such that for each edge $(u,v)$ $u$ and $v$ are in different sets 686 | \ei 687 | \begin{figure} 688 | \begin{tikzpicture}[scale=1.8,auto,swap] 689 | \only<-1>{ 690 | \node[vertex] (0) at (0,0.5) {0}; 691 | } 692 | \only<2->{ 693 | \node[vertex] (0) at (0,0) {0}; 694 | } 695 | \node[vertex] (1) at (0.8,1) {1}; 696 | \node[vertex] (2) at (0.8,0) {2}; 697 | \only<-3>{ 698 | \node[vertex] (3) at (2,1) {3}; 699 | \node[vertex] (4) at (1.8,0.5) {4}; 700 | \node[vertex] (5) at (1.6,0) {5}; 701 | } 702 | \only<4->{ 703 | \node[vertex] (3) at (2,0) {3}; 704 | \node[vertex] (4) at (1.6,0) {4}; 705 | \node[vertex] (5) at (1.2,0) {5}; 706 | } 707 | \only<-2>{ 708 | \node[vertex] (6) at (0,-0.5) {6}; 709 | } 710 | \only<3->{ 711 | \node[vertex] (6) at (0,1) {6}; 712 | } 713 | 714 | \path[edge] (0) -- (1); 715 | \path[edge] (0) -- (6); 716 | \path[edge] (6) -- (2); 717 | \path[edge] (1) -- (2); 718 | \path[edge] (1) -- (3); 719 | \path[edge] (1) -- (4); 720 | \path[edge] (1) -- (5); 721 | 722 | \onslide<5->{ 723 | \draw[color=vhilight] (0.4,1) ellipse (0.7cm and 0.3cm); 724 | \draw[color=vhilight] (1.0,0) ellipse (1.5cm and 0.3cm); 725 | } 726 | 727 | \pgfresetboundingbox 728 | \path [use as bounding box] (1.5,0) rectangle (1,1.2); 729 | \end{tikzpicture} 730 | \end{figure} 731 | 732 | \vspace{20pt} 733 | \bi 734 | \item How do we check if a graph is bipartite? 735 | \ei 736 | \end{frame} 737 | 738 | \begin{frame}{Bipartite graphs} 739 | \bi 740 | \item We want to check if we can split the vertices into these two groups 741 | \item Take any vertex, and assume that it's in the first group 742 | \item Then all of his neighbors must be in the second group 743 | \item And then all of their neighbors must be in the first group 744 | \item And so on... 745 | \vspace{10pt} 746 | \item We can do this with a simple depth-first search 747 | \item If we ever find a contradiction (i.e.\ a vertex must both be in the first and second set), then the graph is not bipartite 748 | \ei 749 | \end{frame} 750 | 751 | \begin{frame}[fragile]{Bipartite graphs} 752 | \begin{minted}[fontsize=\scriptsize]{cpp} 753 | vector adj[1000]; 754 | vector side(1000, -1); 755 | bool is_bipartite = true; 756 | 757 | void check_bipartite(int u) { 758 | for (int i = 0; i < adj[u].size(); i++) { 759 | int v = adj[u][i]; 760 | if (side[v] == -1) { 761 | side[v] = 1 - side[u]; 762 | check_bipartite(v); 763 | } else if (side[u] == side[v]) { 764 | is_bipartite = false; 765 | } 766 | } 767 | } 768 | 769 | for (int u = 0; u < n; u++) { 770 | if (side[u] == -1) { 771 | side[u] = 0; 772 | check_bipartite(u); 773 | } 774 | } 775 | \end{minted} 776 | \end{frame} 777 | 778 | \begin{frame}{Coloring bipartite graphs} 779 | \bi 780 | \item What if we want to find the minimum graph coloring of a bipartite graph? 781 | \ei 782 | 783 | \begin{figure} 784 | \begin{tikzpicture}[scale=1.8,auto,swap] 785 | \onslide<-1>{ 786 | \node[vertex] (0) at (0,0) {0}; 787 | \node[vertex] (1) at (0.8,1) {1}; 788 | \node[vertex] (2) at (0.8,0) {2}; 789 | \node[vertex] (3) at (2,0) {3}; 790 | \node[vertex] (4) at (1.6,0) {4}; 791 | \node[vertex] (5) at (1.2,0) {5}; 792 | \node[vertex] (6) at (0,1) {6}; 793 | } 794 | \onslide<2->{ 795 | \node[vertex1] (0) at (0,0) {0}; 796 | \node[vertex3] (1) at (0.8,1) {1}; 797 | \node[vertex1] (2) at (0.8,0) {2}; 798 | \node[vertex1] (3) at (2,0) {3}; 799 | \node[vertex1] (4) at (1.6,0) {4}; 800 | \node[vertex1] (5) at (1.2,0) {5}; 801 | \node[vertex3] (6) at (0,1) {6}; 802 | } 803 | 804 | \path[edge] (0) -- (1); 805 | \path[edge] (0) -- (6); 806 | \path[edge] (6) -- (2); 807 | \path[edge] (1) -- (2); 808 | \path[edge] (1) -- (3); 809 | \path[edge] (1) -- (4); 810 | \path[edge] (1) -- (5); 811 | 812 | \pgfresetboundingbox 813 | \path [use as bounding box] (1.5,0) rectangle (1,1.2); 814 | \end{tikzpicture} 815 | \end{figure} 816 | 817 | \vspace{20pt} 818 | \bi 819 | \item<2-> Simple, one side can be colored with one color, and the second side can be colored with a second color 820 | \ei 821 | \end{frame} 822 | 823 | \begin{frame}{Bipartite matching} 824 | \bi 825 | \item Finding a maximum matching in bipartite graphs is very common 826 | \item \textit{see example} 827 | \vspace{10pt} 828 | \item Soon we'll see an efficient algorithm for finding the maximum matching in a bipartite graph 829 | \ei 830 | \end{frame} 831 | 832 | \begin{frame}{König's theorem} 833 | \bi 834 | \item König's theorem states that the size of a minimum vertex cover in a bipartite graph is equal to the size of the maximum matching in that graph 835 | \vspace{10pt} 836 | \item To find the minimum vertex cover in a bipartite graph, we just find the maximum matching with our efficient algorithm, and we have our answer 837 | \item And since the size of the maximum independent set is just the number of vertices minus the size of the minimum vertex cover, we can also compute the maximum independent set for a bipartite graph efficiently 838 | \ei 839 | \end{frame} 840 | 841 | \begin{frame}{Trees} 842 | \bi 843 | \item An undirected graph is a tree if it has no cycles 844 | \vspace{10pt} 845 | \item Easy to check if a graph is a tree by checking if there are any backward edges in the depth-first search tree (see previous lecture) 846 | \vspace{10pt} 847 | \item A connected tree with $n$ vertices has exactly $n-1$ edges 848 | \vspace{10pt} 849 | \item Between each pair of vertices $u,v$ in the tree, there exists exactly one simple path, which can be found with depth-first search (or breadth-first search) 850 | \ei 851 | \end{frame} 852 | 853 | \begin{frame}{Trees} 854 | \bi 855 | \item What if we look at these problems for trees? 856 | \vspace{10pt} 857 | \item How do we find the minimum number of colors needed to color a tree? 858 | 859 | \onslide<2->{ 860 | \vspace{10pt} 861 | \item Well, trees are actually bipartite graphs... 862 | \item Why? Pick some vertex and make it the root of the tree. Then vertices at even heights in the tree can be put on one side, and vertices at odd heights can be put on the other side 863 | \vspace{10pt} 864 | \item So all the efficient algorithms for bipartite graphs also work for trees 865 | } 866 | \ei 867 | \end{frame} 868 | 869 | \begin{frame}{Trees} 870 | \bi 871 | \item Trees are also well suited for dynamic programming, so many problems become simpler here because of that 872 | \ei 873 | \end{frame} 874 | 875 | \begin{frame}{Directed acyclic graphs} 876 | \bi 877 | \item A directed graph is a directed acyclic graph if it doesn't contain any cycles 878 | \vspace{10pt} 879 | \item Easy to check if a graph is a DAG by checking if there are any backward edges in the depth-first search tree (see previous lecture) 880 | \vspace{10pt} 881 | \item Many problems are simple on DAGs, since it's easy to do dynamic programming over DAGs 882 | \bi 883 | \item counting number of simple paths from $u$ to $v$ 884 | \item longest simple path from $u$ to $v$ 885 | \ei 886 | \ei 887 | \end{frame} 888 | 889 | \end{document} 890 | 891 | -------------------------------------------------------------------------------- /08_graphs_2/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/08_graphs_2/kattis.png -------------------------------------------------------------------------------- /09_mathematics/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 9: Mathematics 2 | 3 | Covers some basic topics in mathematics, including number theory, combinatorics and game theory. 4 | 5 |

Problems

6 | Solve some of the following problems on Kattis. You need 4 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 | -------------------------------------------------------------------------------- /09_mathematics/aflv_10_mathematics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/09_mathematics/aflv_10_mathematics.pdf -------------------------------------------------------------------------------- /09_mathematics/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/09_mathematics/kattis.png -------------------------------------------------------------------------------- /09a_problem_session_2/README.md: -------------------------------------------------------------------------------- 1 | # Problem session 2 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 | -------------------------------------------------------------------------------- /10_graphs_3_network_flow/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 10: Network flow 2 | 3 | Covers maximum flow, minimum cut, bipartite matching, and other applications. 4 | 5 |

Material

6 | 9 |

Problems

10 | Solve some of the following problems on Kattis. You need 3 points to get full score. 11 | 18 |

Bonus problems

19 | If you want a challenge, you can try solving the following bonus problems. 20 | 24 | -------------------------------------------------------------------------------- /10_graphs_3_network_flow/bipartite_matching_2.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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | const int INF = 2147483647; 26 | typedef long long ll; 27 | typedef pair ii; 28 | typedef vector vi; 29 | typedef vector vii; 30 | typedef vector vvi; 31 | typedef vector vvii; 32 | template int size(T &x) { return x.size(); } 33 | 34 | // assert or gtfo 35 | 36 | struct flow_network { 37 | 38 | struct edge { 39 | int u, v, cap; 40 | edge *rev; 41 | bool forward; 42 | edge(int _u, int _v, int _cap, bool forw) 43 | : u(_u), v(_v), cap(_cap), forward(forw) { } 44 | }; 45 | 46 | int n; 47 | vector > adj; 48 | flow_network(int _n) : n(_n), adj(_n) { } 49 | 50 | void add_edge(int u, int v, int cap) { 51 | edge *e = new edge(u, v, cap, true); 52 | edge *rev = new edge(v, u, 0, false); 53 | e->rev = rev; 54 | rev->rev = e; 55 | adj[u].push_back(e); 56 | adj[v].push_back(rev); 57 | } 58 | 59 | int augment(int s, int t) { 60 | vector back(n, (edge*)0); 61 | queue Q; 62 | Q.push(s); 63 | back[s] = (edge*)1; 64 | while (!Q.empty()) { 65 | int u = Q.front(); Q.pop(); 66 | for (int i = 0; i < adj[u].size(); i++) { 67 | int v = adj[u][i]->v; 68 | if (back[v] == NULL && adj[u][i]->cap > 0) { 69 | back[v] = adj[u][i]; 70 | Q.push(v); 71 | } 72 | } 73 | } 74 | 75 | if (back[t] == NULL) 76 | return 0; 77 | 78 | stack S; 79 | S.push(back[t]); 80 | int bneck = back[t]->cap; 81 | while (S.top()->u != s) { 82 | S.push(back[S.top()->u]); 83 | bneck = min(bneck, S.top()->cap); 84 | } 85 | 86 | while (!S.empty()) { 87 | S.top()->cap -= bneck; 88 | S.top()->rev->cap += bneck; 89 | S.pop(); 90 | } 91 | 92 | return bneck; 93 | } 94 | 95 | int max_flow(int source, int sink) { 96 | int flow = 0; 97 | while (true) { 98 | int f = augment(source, sink); 99 | if (f == 0) { 100 | break; 101 | } 102 | 103 | flow += f; 104 | } 105 | 106 | return flow; 107 | } 108 | }; 109 | 110 | int main() 111 | { 112 | int l, r, m; 113 | scanf("%d %d %d\n", &l, &r, &m); 114 | 115 | int SOURCE = 0, 116 | SINK = 1, 117 | LEFT = 2, 118 | RIGHT = LEFT + l, 119 | CNT = RIGHT + r; 120 | 121 | flow_network g(CNT); 122 | 123 | for (int i = 0; i < m; i++) { 124 | int a, b; 125 | scanf("%d %d\n", &a, &b); 126 | 127 | g.add_edge(LEFT + a, RIGHT + b, 1); 128 | } 129 | 130 | for (int i = 0; i < l; i++) { 131 | g.add_edge(SOURCE, LEFT + i, 1); 132 | } 133 | 134 | for (int i = 0; i < r; i++) { 135 | g.add_edge(RIGHT + i, SINK, 1); 136 | } 137 | 138 | 139 | cout << g.max_flow(SOURCE, SINK) << endl; 140 | 141 | for (int u = 0; u < l; u++) { 142 | for (int i = 0; i < g.adj[LEFT + u].size(); i++) { 143 | 144 | if (g.adj[LEFT + u][i]->forward) { 145 | 146 | printf("%d %d %d\n", u, g.adj[LEFT + u][i]->v - RIGHT, g.adj[LEFT + u][i]->rev->cap); 147 | } 148 | } 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | -------------------------------------------------------------------------------- /10_graphs_3_network_flow/flow_network.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct flow_network { 8 | 9 | struct edge { 10 | int u, v, cap; 11 | edge *rev; 12 | bool forward; 13 | edge(int _u, int _v, int _cap, bool forw) 14 | : u(_u), v(_v), cap(_cap), forward(forw) { } 15 | }; 16 | 17 | int n; 18 | vector > adj; 19 | flow_network(int _n) : n(_n), adj(_n) { } 20 | 21 | void add_edge(int u, int v, int cap) { 22 | edge *e = new edge(u, v, cap, true); 23 | edge *rev = new edge(v, u, 0, false); 24 | e->rev = rev; 25 | rev->rev = e; 26 | adj[u].push_back(e); 27 | adj[v].push_back(rev); 28 | } 29 | 30 | int augment(int s, int t) { 31 | vector back(n, (edge*)0); 32 | queue Q; 33 | Q.push(s); 34 | back[s] = (edge*)1; 35 | while (!Q.empty()) { 36 | int u = Q.front(); Q.pop(); 37 | for (int i = 0; i < adj[u].size(); i++) { 38 | int v = adj[u][i]->v; 39 | if (back[v] == NULL && adj[u][i]->cap > 0) { 40 | back[v] = adj[u][i]; 41 | Q.push(v); 42 | } 43 | } 44 | } 45 | 46 | if (back[t] == NULL) 47 | return 0; 48 | 49 | stack S; 50 | S.push(back[t]); 51 | int bneck = back[t]->cap; 52 | while (S.top()->u != s) { 53 | S.push(back[S.top()->u]); 54 | bneck = min(bneck, S.top()->cap); 55 | } 56 | 57 | while (!S.empty()) { 58 | S.top()->cap -= bneck; 59 | S.top()->rev->cap += bneck; 60 | S.pop(); 61 | } 62 | 63 | return bneck; 64 | } 65 | 66 | int max_flow(int source, int sink) { 67 | int flow = 0; 68 | while (true) { 69 | int f = augment(source, sink); 70 | if (f == 0) { 71 | break; 72 | } 73 | 74 | flow += f; 75 | } 76 | 77 | return flow; 78 | } 79 | }; 80 | 81 | int main() { 82 | 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /10_graphs_3_network_flow/internet.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 flow_network { 13 | 14 | struct edge { 15 | int u, v, cap; 16 | edge *rev; 17 | bool forward; 18 | edge(int _u, int _v, int _cap, bool forw) 19 | : u(_u), v(_v), cap(_cap), forward(forw) { } 20 | }; 21 | 22 | int n; 23 | vector > adj; 24 | flow_network(int _n) : n(_n), adj(_n) { } 25 | 26 | void add_edge(int u, int v, int cap) { 27 | edge *e = new edge(u, v, cap, true); 28 | edge *rev = new edge(v, u, 0, false); 29 | e->rev = rev; 30 | rev->rev = e; 31 | adj[u].push_back(e); 32 | adj[v].push_back(rev); 33 | } 34 | 35 | int augment(int s, int t) { 36 | vector back(n, (edge*)0); 37 | queue Q; 38 | Q.push(s); 39 | back[s] = (edge*)1; 40 | while (!Q.empty()) { 41 | int u = Q.front(); Q.pop(); 42 | for (int i = 0; i < adj[u].size(); i++) { 43 | int v = adj[u][i]->v; 44 | if (back[v] == NULL && adj[u][i]->cap > 0) { 45 | back[v] = adj[u][i]; 46 | Q.push(v); 47 | } 48 | } 49 | } 50 | 51 | if (back[t] == NULL) 52 | return 0; 53 | 54 | stack S; 55 | S.push(back[t]); 56 | int bneck = back[t]->cap; 57 | while (S.top()->u != s) { 58 | S.push(back[S.top()->u]); 59 | bneck = min(bneck, S.top()->cap); 60 | } 61 | 62 | while (!S.empty()) { 63 | S.top()->cap -= bneck; 64 | S.top()->rev->cap += bneck; 65 | S.pop(); 66 | } 67 | 68 | return bneck; 69 | } 70 | 71 | int max_flow(int source, int sink) { 72 | int flow = 0; 73 | while (true) { 74 | int f = augment(source, sink); 75 | if (f == 0) { 76 | break; 77 | } 78 | 79 | flow += f; 80 | } 81 | 82 | return flow; 83 | } 84 | }; 85 | 86 | int main() { 87 | int n; 88 | int at = 1; 89 | while (cin >> n && n != 0) { 90 | flow_network G(n); 91 | 92 | int s, t, m; 93 | cin >> s >> t >> m; 94 | s--, t--; 95 | for (int i = 0; i < m; i++) { 96 | int u, v, c; 97 | cin >> u >> v >> c; 98 | u--, v--; 99 | G.add_edge(u, v, c); 100 | G.add_edge(v, u, c); 101 | } 102 | 103 | cout << "Network " << (at++) << endl; 104 | cout << "The bandwidth is " << G.max_flow(s, t) << "." << endl; 105 | cout << endl; 106 | } 107 | 108 | return 0; 109 | } 110 | 111 | -------------------------------------------------------------------------------- /10_graphs_3_network_flow/tshirts_3.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 flow_network { 13 | 14 | struct edge { 15 | int u, v, cap; 16 | edge *rev; 17 | bool forward; 18 | edge(int _u, int _v, int _cap, bool forw) 19 | : u(_u), v(_v), cap(_cap), forward(forw) { } 20 | }; 21 | 22 | int n; 23 | vector > adj; 24 | flow_network(int _n) : n(_n), adj(_n) { } 25 | 26 | void add_edge(int u, int v, int cap) { 27 | edge *e = new edge(u, v, cap, true); 28 | edge *rev = new edge(v, u, 0, false); 29 | e->rev = rev; 30 | rev->rev = e; 31 | adj[u].push_back(e); 32 | adj[v].push_back(rev); 33 | } 34 | 35 | int augment(int s, int t) { 36 | vector back(n, (edge*)0); 37 | queue Q; 38 | Q.push(s); 39 | back[s] = (edge*)1; 40 | while (!Q.empty()) { 41 | int u = Q.front(); Q.pop(); 42 | for (int i = 0; i < adj[u].size(); i++) { 43 | int v = adj[u][i]->v; 44 | if (back[v] == NULL && adj[u][i]->cap > 0) { 45 | back[v] = adj[u][i]; 46 | Q.push(v); 47 | } 48 | } 49 | } 50 | 51 | if (back[t] == NULL) 52 | return 0; 53 | 54 | stack S; 55 | S.push(back[t]); 56 | int bneck = back[t]->cap; 57 | while (S.top()->u != s) { 58 | S.push(back[S.top()->u]); 59 | bneck = min(bneck, S.top()->cap); 60 | } 61 | 62 | while (!S.empty()) { 63 | S.top()->cap -= bneck; 64 | S.top()->rev->cap += bneck; 65 | S.pop(); 66 | } 67 | 68 | return bneck; 69 | } 70 | 71 | int max_flow(int source, int sink) { 72 | int flow = 0; 73 | while (true) { 74 | int f = augment(source, sink); 75 | if (f == 0) { 76 | break; 77 | } 78 | 79 | flow += f; 80 | } 81 | 82 | return flow; 83 | } 84 | }; 85 | 86 | int main() { 87 | map num; 88 | num["XS"] = 0; 89 | num["S"] = 1; 90 | num["M"] = 2; 91 | num["L"] = 3; 92 | num["XL"] = 4; 93 | num["XXL"] = 5; 94 | 95 | int ts; 96 | cin >> ts; 97 | for (int t = 0; t < ts; t++) { 98 | 99 | int n, m; 100 | cin >> n >> m; 101 | 102 | int SOURCE = 0, 103 | SINK = 1, 104 | LEFT = 2, 105 | RIGHT = LEFT + size(num), 106 | CNT = RIGHT + m; 107 | 108 | flow_network G(CNT); 109 | 110 | for (int i = 0; i < m; i++) { 111 | string a, b; 112 | cin >> a >> b; 113 | G.add_edge(LEFT + num[a], RIGHT + i, 1); 114 | G.add_edge(LEFT + num[b], RIGHT + i, 1); 115 | } 116 | 117 | for (int i = 0; i < size(num); i++) { 118 | G.add_edge(SOURCE, LEFT + i, n/6); 119 | } 120 | for (int i = 0; i < m; i++) { 121 | G.add_edge(RIGHT + i, SINK, 1); 122 | } 123 | 124 | cout << G.max_flow(SOURCE, SINK) << endl; 125 | for (int i = 0; i < size(num); i++) { 126 | for (int j = 0; j < size(G.adj[LEFT + i]); j++) { 127 | if (G.adj[LEFT+i][j]->forward && G.adj[LEFT+i][j]->cap == 0) { 128 | cout << "tshirts " << i << ", volunteer " << (G.adj[LEFT+i][j]->v - RIGHT) << endl; 129 | } 130 | } 131 | } 132 | } 133 | return 0; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /11_strings/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 11: Strings 2 | 3 | Covers string matching, KMP, tries, suffix arrays, and applications. 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 | -------------------------------------------------------------------------------- /11_strings/aflv_11_strings.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/11_strings/aflv_11_strings.pdf -------------------------------------------------------------------------------- /11_strings/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/11_strings/kattis.png -------------------------------------------------------------------------------- /11_strings/kmp.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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define all(o) (o).begin(), (o).end() 24 | #define allr(o) (o).rbegin(), (o).rend() 25 | const int INF = 2147483647; 26 | typedef long long ll; 27 | typedef pair ii; 28 | typedef vector vi; 29 | typedef vector vii; 30 | typedef vector vvi; 31 | typedef vector vvii; 32 | template int size(T &x) { return x.size(); } 33 | 34 | // assert or gtfo 35 | 36 | int* compute_pi(const string &t) { 37 | 38 | int m = t.size(); 39 | int *pi = new int[m + 1]; 40 | if (0 <= m) pi[0] = 0; 41 | if (1 <= m) pi[1] = 0; 42 | for (int i = 2; i <= m; i++) { 43 | for (int j = pi[i - 1]; ; j = pi[j]) { 44 | if (t[j] == t[i - 1]) { 45 | pi[i] = j + 1; 46 | break; 47 | } 48 | if (j == 0) { 49 | pi[i] = 0; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | return pi; 56 | } 57 | 58 | int string_match(const string &s, const string &t) { 59 | 60 | int n = s.size(), 61 | m = t.size(); 62 | 63 | int *pi = compute_pi(t); 64 | 65 | for (int i = 0, j = 0; i < n; ) { 66 | if (s[i] == t[j]) { 67 | i++; j++; 68 | if (j == m) { 69 | return i - m; 70 | } 71 | } 72 | else if (j > 0) j = pi[j]; 73 | else i++; 74 | } 75 | 76 | delete[] pi; 77 | return -1; 78 | } 79 | 80 | int main() 81 | { 82 | string s = "banani"; 83 | string t = "nan"; 84 | 85 | printf("%d\n", string_match(s, t)); 86 | 87 | return 0; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /11_strings/longest_common_substring_3.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 suffix_array { 13 | struct entry { 14 | pair nr; 15 | int p; 16 | 17 | bool operator <(const entry &other) const { 18 | return nr < other.nr; 19 | } 20 | }; 21 | 22 | string s; 23 | int n; 24 | vector > P; 25 | vector L; 26 | vector idx; 27 | 28 | suffix_array(string _s) : s(_s), n(s.size()) { 29 | L = vector(n); 30 | P.push_back(vector(n)); 31 | idx = vector(n); 32 | 33 | for (int i = 0; i < n; i++) { 34 | P[0][i] = s[i]; 35 | } 36 | 37 | for (int stp = 1, cnt = 1; (cnt >> 1) < n; stp++, cnt <<= 1) { 38 | P.push_back(vector(n)); 39 | for (int i = 0; i < n; i++) { 40 | L[i].p = i; 41 | L[i].nr = make_pair(P[stp - 1][i], 42 | i + cnt < n ? P[stp - 1][i + cnt] : -1); 43 | } 44 | 45 | sort(L.begin(), L.end()); 46 | for (int i = 0; i < n; i++) { 47 | if (i > 0 && L[i].nr == L[i - 1].nr) { 48 | P[stp][L[i].p] = P[stp][L[i - 1].p]; 49 | } else { 50 | P[stp][L[i].p] = i; 51 | } 52 | } 53 | } 54 | 55 | for (int i = 0; i < n; i++) { 56 | idx[P[P.size() - 1][i]] = i; 57 | } 58 | } 59 | 60 | int lcp(int x, int y) { 61 | int res = 0; 62 | if (x == y) return n - x; 63 | for (int k = P.size() - 1; k >= 0 && x < n && y < n; k--) { 64 | if (P[k][x] == P[k][y]) { 65 | x += 1 << k; 66 | y += 1 << k; 67 | res += 1 << k; 68 | } 69 | } 70 | return res; 71 | } 72 | }; 73 | 74 | int main() { 75 | string s = "baaaaaaanaaaaaannnnnnnnniiiiiiiiiiiii"; 76 | string t = "kaaaaaaaaaaaaaaannnnnniiiiiiinnnnnnnnnnnnaaaa"; 77 | string r = s + "$" + t; 78 | 79 | suffix_array sa(r); 80 | 81 | int mx = 0, 82 | mxi = -1; 83 | for (int i = 0; i+1 < size(r); i++) { 84 | bool a_in_s = sa.idx[i] < size(s), 85 | b_in_s = sa.idx[i+1] < size(s); 86 | 87 | if (a_in_s != b_in_s) { 88 | int l = sa.lcp(sa.idx[i], sa.idx[i+1]); 89 | if (l > mx) { 90 | mx = l; 91 | mxi = sa.idx[i]; 92 | } 93 | } 94 | } 95 | 96 | cout << mx << endl; 97 | cout << r.substr(mxi, mx) << endl; 98 | 99 | return 0; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /11_strings/suffix_array_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 | struct suffix_array { 13 | struct entry { 14 | pair nr; 15 | int p; 16 | 17 | bool operator <(const entry &other) const { 18 | return nr < other.nr; 19 | } 20 | }; 21 | 22 | string s; 23 | int n; 24 | vector > P; 25 | vector L; 26 | vector idx; 27 | 28 | suffix_array(string _s) : s(_s), n(s.size()) { 29 | L = vector(n); 30 | P.push_back(vector(n)); 31 | idx = vector(n); 32 | 33 | for (int i = 0; i < n; i++) { 34 | P[0][i] = s[i]; 35 | } 36 | 37 | for (int stp = 1, cnt = 1; (cnt >> 1) < n; stp++, cnt <<= 1) { 38 | P.push_back(vector(n)); 39 | for (int i = 0; i < n; i++) { 40 | L[i].p = i; 41 | L[i].nr = make_pair(P[stp - 1][i], 42 | i + cnt < n ? P[stp - 1][i + cnt] : -1); 43 | } 44 | 45 | sort(L.begin(), L.end()); 46 | for (int i = 0; i < n; i++) { 47 | if (i > 0 && L[i].nr == L[i - 1].nr) { 48 | P[stp][L[i].p] = P[stp][L[i - 1].p]; 49 | } else { 50 | P[stp][L[i].p] = i; 51 | } 52 | } 53 | } 54 | 55 | for (int i = 0; i < n; i++) { 56 | idx[P[P.size() - 1][i]] = i; 57 | } 58 | } 59 | 60 | int lcp(int x, int y) { 61 | int res = 0; 62 | if (x == y) return n - x; 63 | for (int k = P.size() - 1; k >= 0 && x < n && y < n; k--) { 64 | if (P[k][x] == P[k][y]) { 65 | x += 1 << k; 66 | y += 1 << k; 67 | res += 1 << k; 68 | } 69 | } 70 | return res; 71 | } 72 | }; 73 | 74 | int main() { 75 | string s = "kanina"; 76 | suffix_array sa(s); 77 | 78 | for (int i = 0; i < size(s); i++) { 79 | cout << sa.idx[i] << " " << s.substr(sa.idx[i]) << endl; 80 | } 81 | 82 | cout << sa.lcp(1,5) << endl; 83 | 84 | return 0; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /12_geometry/README.md: -------------------------------------------------------------------------------- 1 | # Lecture 12: Geometry 2 | 3 | Covers basic geometry, convex hulls, area of polygons, point in polygon, and closest pair of points. 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 | -------------------------------------------------------------------------------- /12_geometry/aflv_12_geometry.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/12_geometry/aflv_12_geometry.pdf -------------------------------------------------------------------------------- /12_geometry/geometry.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | #define P(p) const point &p 4 | #define L(p0, p1) P(p0), P(p1) 5 | #define C(p0, r) P(p0), double r 6 | #define PP(pp) pair &pp 7 | typedef complex point; 8 | const double pi = acos(-1.0); 9 | const double EPS = 1e-9; 10 | double dot(P(a), P(b)) { 11 | return real(conj(a) * b); 12 | } 13 | double cross(P(a), P(b)) { 14 | return imag(conj(a) * b); 15 | } 16 | point rotate(P(p), double radians = pi / 2, P(about) = point(0,0)) { 17 | return (p - about) * exp(point(0, radians)) + about; 18 | } 19 | point proj(P(u), P(v)) { 20 | return dot(u, v) / dot(u, u) * u; 21 | } 22 | point normalize(P(p), double k = 1.0) { 23 | return abs(p) == 0 ? point(0,0) : p / abs(p) * k; 24 | } 25 | bool parallel(L(a, b), L(p, q)) { 26 | return abs(cross(b - a, q - p)) < EPS; 27 | } 28 | double ccw(P(a), P(b), P(c)) { 29 | return cross(b - a, c - b); 30 | } 31 | bool collinear(P(a), P(b), P(c)) { return abs(ccw(a, b, c)) < EPS; } 32 | double angle(P(a), P(b), P(c)) { 33 | return acos(dot(b - a, c - b) / abs(b - a) / abs(c - b)); 34 | } 35 | bool intersect(L(a, b), L(p, q), point &res, bool segment = false) { 36 | // NOTE: check for parallel/collinear lines before calling this function 37 | point r = b - a, s = q - p; 38 | double c = cross(r, s), t = cross(p - a, s) / c, u = cross(p - a, r) / c; 39 | if (segment && (t < 0-EPS || t > 1+EPS || u < 0-EPS || u > 1+EPS)) 40 | return false; 41 | res = a + t * r; 42 | return true; 43 | } 44 | point closest_point(L(a, b), P(c), bool segment = false) { 45 | if (segment) { 46 | if (dot(b - a, c - b) > 0) return b; 47 | if (dot(a - b, c - a) > 0) return a; 48 | } 49 | double t = dot(c - a, b - a) / norm(b - a); 50 | return a + t * (b - a); 51 | } 52 | 53 | typedef vector polygon; 54 | #define MAXN 1000 55 | point hull[MAXN]; 56 | bool cmp(const point &a, const point &b) { 57 | return abs(real(a) - real(b)) > EPS ? 58 | real(a) < real(b) : imag(a) < imag(b); } 59 | int convex_hull(vector p) { 60 | int n = p.size(), l = 0; 61 | sort(p.begin(), p.end(), cmp); 62 | for (int i = 0; i < n; i++) { 63 | if (i > 0 && p[i] == p[i - 1]) 64 | continue; 65 | while (l >= 2 && ccw(hull[l - 2], hull[l - 1], p[i]) >= 0) 66 | l--; 67 | hull[l++] = p[i]; 68 | } 69 | int r = l; 70 | for (int i = n - 2; i >= 0; i--) { 71 | if (p[i] == p[i + 1]) 72 | continue; 73 | while (r - l >= 1 && ccw(hull[r - 2], hull[r - 1], p[i]) >= 0) 74 | r--; 75 | hull[r++] = p[i]; 76 | } 77 | return l == 1 ? 1 : r - 1; 78 | } 79 | -------------------------------------------------------------------------------- /12_geometry/kattis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuprDewd/T-414-AFLV/a9a9d8402e7e6395a2de2fed4af829398cbbac3c/12_geometry/kattis.png -------------------------------------------------------------------------------- /12a_final_exam/README.md: -------------------------------------------------------------------------------- 1 | # Final exam 2 | 3 | At the end of the course there was a four-hour individual final exam. It was as follows. 4 |

Part 1 (35%)

5 | Solve one of the following problems. 6 | 10 |

Part 2 (15%)

11 | Solve one of the following problems. 12 | 15 |

Part 3 (15%)

16 | Solve one of the following problems. 17 | 21 |

Part 4 (15%)

22 | Solve one of the following problems. 23 | 27 |

Part 5 (15%)

28 | Solve one of the following problems. 29 | 33 |

Part 6 (15%)

34 | Solve one of the following problems. 35 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | https://creativecommons.org/licenses/by/4.0/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # T-414-ÁFLV: A Competitive Programming Course 2 | 3 | This repository contains the course material from T-414-ÁFLV, a competitive 4 | programming course taught at Reykjavík University, Iceland. It is a three-week 5 | long course, with a fresh lecture and problem set each day. 6 | 7 | Lecture slides (including LaTeX sources), the problem sets, and other 8 | supporting material can be found in this repository, inside the respective 9 | directories. All problems are available on the [Open 10 | Kattis](https://open.kattis.com/) online judge. 11 | 12 | ## Editions 13 | The course has been held twice, with mostly different problem sets each time: 14 | 15 | - [2016](https://github.com/SuprDewd/T-414-AFLV/tree/2016) 16 | - [2014](https://github.com/SuprDewd/T-414-AFLV/tree/2014) 17 | 18 | ## Adoption 19 | The course (material) has been adopted (and adapted) by a few external sites, including: 20 | - Ulm University, Germany 21 | - Universidad Mayor de San Simón, Bolivia 22 | - Habib University, Pakistan 23 | 24 | Do you know of a site not listed here? I would be happy to hear about it. 25 | --------------------------------------------------------------------------------