You are on page 1of 10

HRVATSKO OTVORENO NATJECANJE IZ

INFORMATIKE

6. KOLO

RJEŠENJA
HONI 2009/2010 Zadatak: KAJAK
6. kolo, 6. ožujka 2010. Autor: Marko Ivanković
Zadatak je moguće rješiti tako da se svakom kajaku dodjeli udaljenost od cilja
te se kajaci poredaju po njoj. Međutim, rješenje koje ne uključuje sortiranje
također postoji. Dovoljno je krenuti od ciljne ravnine, te prolaziti stupac po
stupac, označavajući kajake uzlazno po poziciji. Valja samo obratiti pažnju da
svi kajaci koji se nalaze u istom stupcu, dijele poziciju.

Potrebno znanje:
rad sa nizovima znakova, sortiranje

Kategorija:
sortiranje
HONI 2009/2010 Zadatak NATJECANJE
6. kolo, 6. ožujka 2010. Autor: Marko Ivanković
Rješenje ovog zadatka je pohlepno. Krene se od prve ekipe u rastućem
redosljedu. Ukoliko je ekipa izgubila čamac, proba se posuditi prvo od
susjedne ekipe s manjim brojem, zatim od ekipe s većim. Natjecatelj koji
intuitivno osjeti ovakvo rješenje može početi s rješavanjem.
Dokazati da je ovo rješenje ispravno nije nužno, ali nije ni složeno.
Pogledajmo najmanji startni broj koji ima uništeni čamac. Ukoliko on može
posuditi čamac od ekipe s manjim startnim brojem i učini to, tada smo se
rješili jednog uništenog čamca. Ukoliko on to ne učini, tada taj čamac neće
preuzeti ni jedna ekipa, budući da su ekipe spremne čamce prenositi samo
jedno startno mjesto. Primjenjujući uzastopno takvo razmišljanje, vidimo da
je pohlepno rješenje zaista optimalno.

Potrebno znanje:
pohlepni algoritmi, intuicija

Kategorija:
pohlepni algoritmi
HONI 2009/2010 Zadatak DOSADAN
6. kolo, 6. ožujka 2010. Autor: Marko Ivanković
Ovaj zadatak inspiriran je jednom kriptografskom zagonetkom sa stranice
+Ma's Reversing.
OTP način šifriranja zaista je teorijski savršeno siguran. U svim slučajevima
kad je zakazao zakazao je zbog ljudskog faktora. U ovom zadatku, ključna
informacija je poznavanje strukture izvornog teksta. XOR operacija izvodi se
na binarnom zapisu brojeva, te je prvi korak u zadataku pogledati binarni
zapis izvornog teksta i ključa. Vidimo da mala slova 'a' - 'z' sva na 7 bitu imaju
znamenku '1'. Brojevi '0' - '9' pak na 7 bitu uvijek imaju znamenku 0. Razmak
i točka također na 7 bitu imaju znamenku 0. Iz toga je moguće zaključiti da
će šifriranjem slova uvijek dati brojeve sa 7 bitom postavljenim u 1, a razmak
i točka u 0. To je dovoljna informacija za rješavanje zadatka.

Potrebno znanje:
maštovitost, ASCII kodiranje

Kategorija:
kriptografija
HONI 2009/2010 Zadatak DEJAVU
6. kolo, 6. ožujka 2010. Autor: Bruno Rahle
Dopustite prvo autoru da se ispriča za uvrštavanje ovog zadatka na natjecanje. Ovaj zadatak
je uvršten jer je autor u zadnji tren pomislio da je zadatak koji se trebao nalaziti na njegovom
mjestu (XOR - možete pronaći englesku verziju među zadacima sa istog kola COCI-a) vrlo
sličan jednome zadatku koji se pojavio na jednom drugom natjecanju. Zbog tako kratkog
vremenskog roka (govorimo o nekoliko sati prije natjecanja) ovaj zadatak nije bio pažljivo
testiran, pa su ograničenja vjerojatno bila malo prestroga. Nakon što smo to rekli, pristupimo
analizi zadatka i očekivanom rješenju.
Prvi korak u rješavanju zadatka trebao bi biti analizirati problem vađenja
Y-tog korijena iz X. Ideja kada ručno vadimo korijen najčešće jest da ga
nekom odokativnom metodom pokušamo približno pogoditi. Računalo nema
na raspolaganju ljudski zor, ali jednostavnim dijeljenjem možemo predvidjeti
broj znamenaka traženog broja. (To slijedi iz svojstva logaritama: broj
znamenaka od ≈ .) Nakon što smo

pretpostavili rješenje, potenciramo ga da bismo provjerili je li to doista traženi


broj. Nakon toga, prilagođavamo svoje pretpostavljeno rješenje.
Potenciranje broja može se napraviti prilično jednostavno tako da koristi
ne više od operacija množenja velikih brojeva. (O operaciji množenja
velikih brojeva, nešto kasnije.)
Sada kada znamo otprilike predvidjeti veličinu rješenja te provjeriti jesmo li
ga doista i pronašli, potrebno je osmisliti dobru, brzu i sistematičnu metodu
odabira potencijalnih rješenja. Za to nam, kao stvoreno, dolazi binarno
traženje. Početna granica neka nam bude broj 1, a gornja neki broj koji ima
nekoliko znamenaka više od predviđene granice.
Ono čime smo se do sada bavili jest vađenje korijena iz broja koji se može
spremiti u primitivne tipove podataka. No, brojevi u zadatku to ne mogu.
Stoga je potrebno da to nekako napravimo sami.
Jedna od metoda jest da se broj prikaže kao polinom , gdje je
baza tog broj, a jednoznačno određeni koeficijent za kojeg vrijedi
. Može se pokazati da je za svaku bazu , taj zapis jednoznačan. Kada jednom
odredimo bazu, dovoljno nam je samo pamtiti koeficijente u nizu (tako da je
na prvom mjestu, na drugom, itd.). Na primjer, ako za bazu odaberemo
10, dobit ćemo "standardni" zapis, a ako odaberemo 2, imat ćemo binarni
prikaz.
Prije nego odaberemo bazu, promotrimo prvo problem množenja dva velika
broja (jer kada bismo to znali napraviti, znali bismo i riješiti zadatak do kraja).
U ovome zadatku dovoljno je bilo to napraviti na najjednostavniji način:
svakom znamenkom (u našem slučaju, svakim koeficijentom) prvog broja,
pomnožimo drugi broj te to još pomnožimo s potencijom baze koja odgovara
trenutnoj znamenci prvog broja (da bismo dobili dobru potenciju baze uz
svaki od umnožaka). Na kraju sve te dobivene brojeve sumiramo - naravno,
pazeći da je svaki koeficijent manji od baze (ako je veći, jednostavno ga
"propagiramo" na prvi idući koeficijent). Broj puta koliko se koeficijent prelio
na idući dobije se tako da se koeficijent podijeli sa bazom, a ostatak pri tom
dijeljenju je ono što će ostati od tog koeficijent kada se riješe svi preljevi.

Ako su nam, na, primjer zadana dva "četveroznamenkasta" (tj. imaju četiri
koeficijenta) broja, P i Q, njih možemo zapisati kao:

,
što nakon sređivanja postaje

Da bismo iz toga dobili traženi umnožak u odabranoj bazi, još je potrebno


pobrinuti se da niti jedan koeficijent nije veći od baze. To ćemo napraviti tako
da idemo redom od najnižeg koeficijenta i trenutnom koeficijentu pribrojimo
višak od prošlog (za najniži koeficijent nemamo nikakav višak), novim viškom
proglasimo rezultat cjelobrojnog dijeljenja s bazom, a trenutni koeficijent
postane ostatak pri dijeljenju s bazom.

Sada konačno znamo i množiti dva velika broja (sveli smo ga na množenje i
zbrajanje manjih brojeva). Potrebno je još odabrati dobru bazu. Najčešće se
za bazu uzimaju potencije broja 2 (ako je bitna brzina) ili broja 10 (ako ima
puno čitanja/pisanja), ovisno o potrebi.
Mi ćemo za bazu odabrati broj , budući da nam je brzina bitnija od
jednostavnosti čitanja/pisanja. U tom slučaju, operacija dijeljenja (jedna od
najsporijih operacija za procesor) u toj bazi može se izvesti operacijom
pomicanja bitova (što je, pak, jedna od bržih operacija). Također, i operacija
traženja ostatka je vrlo brza ("and-anje" sa ).
Međutim, postoji problem čitanja i pisanja takvih brojeva. On je, na sreću,
relativno lagano riješiv i ostavljen je čitatelju za vježbu.

Kategorija:
operacije s velikim brojevima
HONI 2009/2010 Zadatak HOLMES
6. kolo, 6. ožujka 2010. Autor: Marko Ivanković
Ovaj zadatak je vrlo sličan traženju dominatora u grafu, ali ipak nije isti. Velik
broj natjecatelja nije primjetio da malo proširenje drugog primjera vodi do
srca problema. Pogledajmo primjer

4 4 1
1 3
2 3
1 4
2 4
3

Događaj 3 je jedina dokazana. Ona je mogla nastati kao rezultat ili događaja
1, ili događaja 2, ili oba. Ali valja primjetiti da je jedan od ta tri uzroka se
MORAO dogoditi, iako neznamo točno koji. Zbog toga je sasvim sigurno da
se i događaj 4 morao dogoditi, iako mu neznamo točan uzrok, već samo skup
mogućih uzorka.
Podijelimo sad graf na tri tipa vrhova. Prvi tip su dokazani događaji. Za
njih znamo da su se dogodili i oni trivijalno ulaze u rješenje. Drugi tip su
svi događaji do kojih postoji put iz dokazanih događaja. Pokretanjem "flood
fill" algoritma iz dokazanih događaja možemo pobrojati sve takve događaje
i ubaciti ih u rješenje. Preostali su samo događaji koji se nalaze "prije"
dokazanih događaja (imaju put koji vodi u dokazane događaje). Kako bi smo
odredili koji od njih također ulazi u rješenje, poslužiti ćemo se sljedećim:
Za svaki događaj, pretpostavimo da nikako nemože biti stvaran. Sada
pokušavamo za što je više događaja pokazati da su možda ostvaren.
Uspijemo li tako možda ostvariti sve dokazane događaje, nikome ništa. Ne
uspijemo li, to znači da je pretpostavka nužno pogrešna i da se ispitivani
događaj morao dogoditi.
Brzina ostvarenja te provjere ključna je za ostvarivanje bodova na zadatku.
Pogledajmo kako najbolje ostvariti tu provjeru. Primjetimo da postoji skup
posebnih vrhova u grafu, koji imaju izlaznih bridova, ali nemaju niti jedan
ulazni brid. Nazovimo takve vrhove aktivatorima. Za svaki vrh možemo
stvoriti skup aktivatora iz kojih postoji put do tog vrha. Ukoliko promatramo
dva vrha, X i Y, te se pitamo "može li vrh Y biti dokazan a da se vrh X
zasigurno nije dogodio" vidimo da je odgovor na pitanje potvrdan ukoliko
postoji barem jedan aktivator koji se nalazi u skupu aktivatora Y, a da u
isto vrijeme nije prisutan u skupu aktivatora vrha X. Ovime možemo vrlo
brzo odrediti odgovor na postavljeno pitanje. Drugo važno opažanje je da su
aktivatora nekog vrha unija svih aktivatora neposrednih roditelja tog vrha.
3
Na prvi pogled čini se da je složenost ovakvog ispitivanja O( N ) kao broj
vrhova * broj vrhova * kardinalni broj skupa aktivatora vrhova. Međutim
pažljivija analiza zadnjeg faktora donosi zanimljive rezultate. Ostavljamo to
na vježbu čitateljima.

Potrebno znanje:
teorija grafova, logika

Kategorija:
teorija grafova
HONI 2009/2010 Zadatak GREMLINI
6. kolo, 6. ožujka 2010. Autor: Luka Kalinovčić

Neka je xD[i] broj godina do rođenja prvog gremlina tipa i koji će imati
duljinu liste predaka jednaku D.
Kako je u laboratorijskoj nesreći nastao po jedan gremlin svakog tipa, vrijedi
x0[i] = 0, za svaki i.
Promotrimo gremlina tipa i duljine liste predaka D. Neka on nakon Y i godina
stvori dlakavu lopticu tipa j, kojoj treba Zi,j godina da se izlegne u gremlina.
Kada se taj gremlin izlegne, imati će duljinu liste predaka D+1.
Stoga je xD+1[j] sigurno manji od ili jednak xD[i] + Yi + Z.
Ako gledamo s druge strane i pitamo se koliko iznosi x D+1[j], tada je očito
da je to najmanja od svih vrijednosti xD[i] + Yi + Zi,j za sve tipove gremlina
i koji stvaraju loptice tipa j.
Jednadžbe možemo zapisati u matričnom obliku:
A ⊗ XD = XD+1
Gdje je matrica A kvadratna, a član u i-tom retku i j-tom stupcu iznosi Yj +
Zj,i
ako gremlin tipa j izliježe lopticu tipa i, ili ∞ ako gremlin tipa j ne izliježe
lopticu tipa i. Matrice XD i XD+1 su vektori koji sadrže vrijednosti xD[i] i
xD+1[i], a operator ⊗ označava min-plus matrično množenje.
Min-plus matrično množenje identično je običnom matričnom množenju osim
što se operacije množenja i zbrajanja zamjenjuju operacijama zbrajanja i
minimuma. Dakle, umjesto množenja radimo zbrajanje, a umjesto zbrajanja
uzimamo minimum dva broja.
Matricu A možemo dignuti na proizvoljnu potenciju D te pogledati rezultantni
vektor XD. Ako su svi brojevi u njemu veći od T, to znaći da ne postoji gremlin
s listom predaka duljine D, u protivnom postoji barem jedan takav. Binarnim
pretraživanjem po broju D možemo pronaći najveću duljinu liste predaka.

Kategorija:
min-plus algebra, matrično potenciranje, binarno pretraživanje

You might also like