Kaj su rješavali naši stari

(Naslov je prilagođen iz imena poznate vrbovačke turističke manifestacije “Kaj su jeli naši stari”.)

Stare Lukine materijale već sam dijelio ovdje i ovdje. Podijelit ću sada i preostala dva dokumenta koja imam:

Luka Kalinovčić: Sweep

Luka Kalinovčić: Dinamičko programiranje

Iz potonjih je zadataka Goran Žužić (naš najuspješniji srednjoškolski natjecatelj dosad) nekad davno naučio dinamiku.

A podijelio bih i članak o FUI koji je Frane Kurtović prije deset godina napisao za časopis PlayMath koji smo tada objavljivali mi, učenici V. gimnazije:

Frane Kurtović: Formula uključivanja i isključivanja

Tip of the day: Stjepanovi snippeti

Kad naučite Python i počnete ga koristiti u stručne ili znanstvene svrhe, više nikada nećete napisati nijedan algoritam: jednostavno ćete iskoristiti neki od desetak tisuća dostupnih modula. Sve je već napisano, čemu duplicirati kod? Malo pretjerujem, naravno, ali nije ovo daleko od istine. Proguglajte malo Python libraries. Naravno, na natjecanju je dostupna samo standardna Python biblioteka, ali natjecanja ćete ionako brzo prerasti.

A do tada, ako se za natjecanja pripremate u C++u, bacite oko na “module” Stjepana Glavine:

https://github.com/stjepang/snippets

Dosta korisno za razne online zadatke, čisto i jednostavno za ubaciti u kod (plug & play). Readme na dnu stranice sve objašnjava. Ako niste upoznati s namespaceovima, primjer korištenja možete vidjeti npr. u rješenju skloniste_flow.cxx u folderu suboptimalnih rješenja s Izbornih priprema (http://hsin.hr/pripreme2019/zadaci/rjesenja.zip).

Naravno, budući da ovo nemate na natjecanjima, ideja je i da vam posluži kao referenca da naučite kako što implementirati. Kad smo već kod toga, prilažem i jedan sličan, stariji dokument, tzv. Zagreb reference (implementacije raznih algoritama) autora Lovre Pužara.

Svako stoblo je stablo, ali nije svako stablo stoblo

[Tema dana: prefiksno stablo iliti STOBLO.]

Prije tjedan dana, na 2. izbornom ispitu pojavio se zadatak sa stablom prefiksa, koje služi da bismo efikasno… Ma skužit ćete iz zadataka.

Ponekad se na crtežu ove strukture slova zapisuju u vrhove stabla. To je pogrešno: slova su bridovi, a ne vrhovi stobla. Vrh nije slovo nego prefiks, tj. niz slova kojima smo došli do tog vrha. Što se tiče implementacije, gledajući rješenja s izbornog ispita, vidio sam da neki koriste pointere, a neki ono što i ja koristim: običnu cjelobrojnu tablicu dimenzija N x 26, gdje je N maksimalan broj vrhova stabla, u kojoj sljedbenik[X][slovo] = Y znači da nakon vrha broj X slijedi slovo kojim dolazimo do vrha broj Y. Ako je ta vrijednost 0 (default), znači da nema tog slova nakon prefiksa X. Dodavanje novog vrha svodi se na operaciju sljedbenik[X][slovo] = broj_vrhova++.

Engleski je trie, a etimologija je zanimljiva (s Wikipedije):

Tries were first described by René de la Briandais in 1959. The term trie was coined by Edward Fredkin, who pronounces it /ˈtr/ (as “tree”), after the middle syllable of retrieval. However, other authors pronounce it /ˈtr/ (as “try”), in an attempt to distinguish it verbally from “tree”.

E sad, u Lijepoj Našoj netko (možda Luka Kalinovčić ili netko prije njega) počeo je ovu strukturu zvati stoblom (logika je jasna: tree –> trie, stablo –> stoblo). Taj pojam i dalje koristimo kolokvijalno. Kraće je reći stoblo nego prefiksno stablo ili stablo prefiksa. Ali nemojte ga baš tako zvati u diplomskom radu, čudno će vas gledati.

Poluosvrt na izborna natjecanja

Za razliku od prijašnjih godina kada se rješavao manji broj zadataka u nešto manjem vremenu, IP ove su godine bile simulacija IOI-a: dva dana po tri zadatka u pet sati. Mislim da su zadatci ispali dobro pogođenih težina i da su pokrili mnoga područja, sva najvažnija (K-ti – strukture podataka, Parking – dinamika, Pokvareni – konstrukcijski zadatak, Izazov – nerješivi zadatak, Sklonište – grafovi, Vezuv – stringovi). Slučajno je tako dobro ispalo, jer teško je to naštimati – dobri zadatci ne padaju s neba. Svaka čast Paljku, Tonku, Bradaču i Bradaču. Između ostalog i na obaranju hrvatskog rekorda za najveće vremensko ograničenje (zadatak Izazov – 15 sekundi), čime je srušen rekord koji su držali zadatci iz devedesetih, a iznosio je impresivnih 10 sekundi.

U rješenjima smo ovaj put (možda i prvi put na hrvatskim natjecanjima općenito?) stavili i folder s alternativnim i suboptimalnim rješenjima na koja se referiraju opisi algoritama. I iz njih se može nešto naučiti.

Još jedan novitet koji se pojavio već na Državnom, a vezan je za moju čudnu privrženost jeziku, jest unaprijeđena terminologija u tekstovima (PDF). Nisu više test podatci nego testni primjeri, a sampleovi/dummyji nisu više primjeri test podataka nego probni primjeri. Jer “test podatci” em je jezično manjkavo (test je imenica, ali je upotrijebljena kao pridjev?!), em je nelogično govoriti o test podatku ako on sadrži, recimo, milijun brojeva – zar nije to milijun podataka? Nego: testni primjeri i probni primjeri, kratko i jasno.

Sad ću možda malo pretjerivati, ali nije to jedino jezično poboljšanje. Naime, kao što nas je jedan lektor u nekom drugom kontekstu upozorio, u sekciji ulaznih podataka dosad smo stalno pisali “U prvom retku nalazi se cijeli broj N” ili “U drugom retku nalazi se N brojeva” itd. Jezik ne voli redundanciju pa ovo nalazi se nije potrebno, dovoljno je koristiti glagol biti. Tako sada (ako se sjetim ispraviti) pišemo “U prvom su retku prirodni brojevi N i M” ili “U drugom je retku N brojeva” itd. Ništa se ne nalazi, naprosto jest.

Možda ću poslije još pisati o samim zadatcima, tj. o nekom od njih. Ovo je ionako samo poluosvrt. Što god to značilo. Evo jedan life hack: ako želite zvučati skromno ili manje ozbiljno, dodajte prefiks polu- ispred toga što predstavljate. Na primjer, ako niste sigurni u svoju ideju, recite da imate poluideju, predložite polurješenje. Ako niste baš pravi matematičar, recite da ste polumatematičar. Nemojte reći ljudima da su nepismeni, nego možda polupismeni ili poluobrazovani. Ili da lonac nije razbijen nego polupan. Eto, toliko za danas.

Tip of the day: broj najkraćih putova i Dijkstrin DAG

Nakon guglanja o tome kaže li se putovi ili putevi, još uvijek nisam siguran što je ovdje ispravno. Kažu da su putovi konkretni, a putevi apstraktni. Za putove u našem smislu, tj. u smislu teorije grafova, može se reći i jedno i drugo. Sigurno su apstraktniji od šumskih putova, ali i konkretniji od, recimo, puteva mudrosti. Odlučio sam se za “konkretnu” varijantu: putovi. (Za one koji se zgražaju nad ovim jezičnim pseudoproblemima: nevažno je, naravno, ali je zabavno, i stvar estetike – shvatite to kao formatiranje teksta.) Dakle: putovi.

Floyd-Warshallov algoritam jedan je od najljepših algoritama koje znam jer u svojih samo 5-6 redaka koda krije mnogo mudrosti (puteva mudrosti, jel). Kao što učinak samog algoritma nije nimalo očit, tako možda nije očito ni da se algoritam može jednostavno nadopuniti tako da izračuna i koliko ima najkraćih putova između svakih dvaju vrhova.

Probajte to sami smisliti. Nije teško, ali je malo tricky. Recimo, prvi odgovor (označen zelenom kvačicom) na Stack Overflowu nije ispravan. Točno rješenje dano je u odgovoru ispod njega (kod počinje s procedure FloydWarshallWithCount ()).

Naravno, mana Floyd-Warshalla je složenost od O(N^3) i zato, osim za guste grafove, prednost ipak ima Dijkstrin algoritam koji se također može nadopuniti tako da računa i broj najkraćih putova.

Evo zadatka gdje to možete isprobati: Šetnja2 (IBT 2010.).

Korišteni bridovi koji se nalaze na najkraćim putovima iz nekog fiksnog vrha čine tzv. Dijkstrin DAG. (Ako su najkraći putovi jedinstveni, riječ je o stablu.) On ima glavnu ulogu u zadatku Najkraći (zadatak dana!) s HONI-ja 2008. (Ako vam je dosad promaklo, rješenja svih HONI-ja možete pronaći ovdje.) Update: još dva zadatka predložio je Marin u komentaru dolje.

Logaritamska struktura i tournament stablo

Stare Lukine materijale počeo sam dijeliti u ovoj objavi, a sada nastavljam. Evo odakle smo (između ostalog) prije 10+ godina učili logaritamsku i tournament, kada su te stvari bile relativno nove, a dobri web materijali o njima rijetki ili nepostojeći:

Luka Kalinovčić: Logaritamska struktura i tournament stablo

Logaritamsku strukturu tako zovu samo u Hrvatskoj, vani je zovu Fenwick tree ili binary indexed tree. Nekad je to bio veliki hit (npr. u zadnjem zadatku na DMIH-u 2006.), a danas je uče već u osnovnoj školi. O naprednijim mogućnostima te strukture pisao sam u ovoj objavi.

Tournament stablo vani zovu segment treeViše o njemu, uključujući i operaciju ažuriranja intervala (lijeni tournament tj. tournament s propagacijom) kao i još neka proširenja možete naći npr. na sljedećim mjestima:

https://csacademy.com/lesson/segment_trees/

https://codeforces.com/blog/entry/15890

Digresija: potapanje brodova

Prije više od deset godina, točnije davne 2007. godine, sunce je sjalo, ruže su mirisale, Hrvatska se pripremala za organizaciju IOI-a, a državno se zvalo DMIH i održavalo se u hotelu Porin u čudnom manje poznatom dijelu Zagreba. (Taj je hotel nedavno bio korišten kao prihvatilište za migrante.) Bio je organiziran neki autobus u neko određeno vrijeme, ali bilo je ljepše i poetičnije na državno natjecanje ići tramvajem do Zapruđa pa pola sata pješice, ili u Zapruđu uhvatiti neki od rijetkih polugradskih autobusa. Isprobati malo divljine i života na rubu. To je ok, štedjelo se za IOI.

Autori zadataka tada su bili legende Lovro Pužar i Luka Kalinovčić, pomagao im je sistemski majstor Marko Ivanković (ono što je danas Matej), a natjecanjima je potpuno dominirao Goran Žužić, i u smislu rezultata i u smislu energije i šarma. Dok su naši kolege prije natjecanja pričali nešto o clockanju (brut/heuristika i nakon 0.9 sekundi ispiši najbolje pronađeno rješenje), Goran je zabacio kosu i komentirao: “Ja sam prva podskupina, nemam ja tu kaj clockat.” Lijepo je to bilo vrijeme, rezultatima je dominirala moja V. gimnazija, koja je do danas potpuno utihnula, izgleda da su prešli na zen budizam.

Na probnom natjecanju tada se pojavio interaktivni zadatak s potapanjem brodova. Trebalo je napisati program koji igra potapanje brodova, tj. pogađa sve protivnikove brodove na 10 x 10 ploči u što manje pokušaja, pri čemu nakon svakog pokušaja program sazna je li brod pogođen. Ima sličnih zadataka online, primjerice:

CodeChef verzija

TopCoder verzija –> Analiza rješenja

THE Analiza

Ono što me zapravo motiviralo da napišem ovaj post jest rješenje Gorana Žužića koje nam je ispričao nakon probnog natjecanja. Za razliku od većine nas koji smo, nakon što bismo prvi put pogodili dio nekog broda, odmah nastavili gađati oko pogođenog polja da bismo pogodili cijeli brod, Goran je radio malo drugačije. On je na početku napravio 20 ili 30 potpuno slučajnih hitaca po cijeloj ploči, neovisno o tome je li neki od njih bio uspješan. Tek potom gledao je koji su hici bili uspješni i prema tome gađao gdje su čitavi brodovi.

Vjerojatno se on toga više i ne sjeća. Nije važno je li to najbolja strategija – ovaj je post ionako digresija. No meni se takva strategija jako svidjela, više u psihološkom nego u matematičkom smislu. Ima taj duh robusnosti, ne lijepi se za prvi pogodak, nego u prvoj fazi decidirano i pomalo nemarno isprobava 30 slučajnih stvari prije nego što se u sljedećoj fazi počne fokusirati. Životna lekcija, eto što je to.