You are on page 1of 8

HRVATSKO OTVORENO NATJECANJE IZ

INFORMATIKE 2013/2014
4. KOLO

OPISI ALGORITAMA
HONI 2013/2014 Zadatak KEFIR
1. kolo, 22. listopada 2012. Autor: Adrian Satja Kurdija

U zadatku treba zbrojiti sljedeća tri broja:


1. ukupna cijena potrošena na bureke (broj_bureka * cijena_bureka),
2. ukupna cijena potrošena na jogurte (broj_jogurata * cijena_jogurta),
3. ukupna cijena potrošena na kefire (broj_kefira * cijena_kefira).

Potrebno znanje: osnovne računske operacije

Kategorija: ad hoc

HONI 2013/2014 Zadatak TEKMA


1. kolo, 22. listopada 2012. Autor: Nikola Dmitrović

Uobičajeno je da su ulazni podaci unaprijed definirani i da se njihov broj ne


mijenja. Ovdje je situacija malo drugačija. Ovisno o ispunjenosti nekog
uvjeta, moglo se pojaviti četiri, šest ili osam prirodnih brojeva na ulazu.
Ako zanemarimo ovu nestandarnost, rješenje zadatka je relativno lako.
Neovisno o razvoju događaja, uvijek moramo učitati četiri broja (X1 , Y1 , X2 ,
X2). Sljedeći redak ulaznih podataka ćemo učitavati samo ako je zbroj golova
domaćina jednak zbroju golova gosta. Nove učitane vrijednosti dodat ćemo
na postojeći broj golova domaćina i gosta te još jednom provjeriti njihovu
jednakost. Na kraju, ovisno o odnosu broja postignutih golova domaćina i
broja golova gosta, odredit ćemo traženi ispis. Detaljan raspis ideje možete
iščitati iz priloženog koda.
Programski kod (pisan u psudojeziku)
ulaz(x1, y1);
ulaz(x2, y2);

domacin := x1 + x2;
gost := y1 + y2;

ako je domacin = gost onda


{
ulaz(xp, yp);
domacin := domacin + xp;
gost := gost + yp;
}
ako je domacin == gost onda
{
ulaz(xj, yj);
domacin := domacin + xj;
gost := gost + yj;
}

ako je domacin > gost onda


izlaz('domacin')
inače:
izlaz('gost');

izlaz(domacin + gost);

Potrebno znanje: naredba učitavanja i ispisivanja, naredba odlučivanja

Kategorija: ad hoc

HONI 2013/2014 Zadatak NASLJEDSTVO


1. kolo, 22. listopada 2012. Autor: Adrian Satja Kurdija

Zadatak je moguće riješiti “matematički”, ispitivanjem nekih slučajeva, što


ostavljamo čitateljici za vježbu, a ovdje opisujemo jednostavnije rješenje.

For-petljom prolazimo po svim mogućim vrijednostima početnoga broja


medaljona M; na primjer, od 1 do 1000. Za svaki takav potencijalni M
provjeravamo je li on jedno od mogućih rješenja. Kako? Najmlađa kći uzela
bi M div N medaljona, što znači da bi ih ostalo M - M div N. Ako je taj broj
jednak stvarnome ostatku O, imamo rješenje. Još je potrebno u dvjema
varijablama pamtiti najmanje i najveće pronađeno rješenje; njih ćemo na
koncu ispisati.

Napomena: div je oznaka za cjelobrojno dijeljenje.

Potrebno znanje: for-petlja

Kategorija: ad hoc

HONI 2013/2014 Zadatak GUMA


1. kolo, 22. listopada 2012. Autor: Matija Bucić

Najprije primijetimo da, ako vertikalni dio valja podijeliti na K dijelova, na


njemu treba biti K - 1 rezova, od kojih su neki produljeni s prethodnih
vertikalnih dijelova, a neki tek započeti. Traženo je rješenje zbroj tek
započetih rezova za sve vertikalne dijelove: na taj način svaki rez brojimo
točno jednom, onda kada smo ga započeli.

Za svaki vertikalni dio zanima nas broj rezova koje ćemo produljiti s
prethodnoga dijela. Pretpostavimo da je prethodni vertikalni dio bio
podijeljen na 30 dijelova, a da trenutni dio valja podijeliti na 70 dijelova.
Primijetimo da su oba broja djeljiva s 10. To znači da prvih 30 dijelova
možemo promatrati kao 10 velikih dijelova po 3, a novih 70 dijelova kao 10
velikih dijelova po 7. Veliki se dijelovi podudaraju i rezove između njih
možemo produljiti. Tih rezova ima 10 - 1 = 9. Preostalih 69 - 9 rezova valja
nam započeti i pribrojiti rješenju.

Iz ovoga primjera možemo zaključiti da je, općenito, broj rezova koji


možemo produljiti s dijela i na dio i + 1 jednak najvećem zajedničkom
djelitelju brojeva ai te ai + 1 umanjenom za jedan. (Primijetimo da se slučaj
kada su brojevi relativno prosti također uklapa u ovu tvrdnju: možemo
produljiti 1 - 1 = 0 rezova.) Dokaz ostavljamo čitateljici za vježbu. Najveći
zajednički djelitelj računamo npr. koristeći Euklidov algoritam, jer je naivna
metoda prespora za velike test podatke.

Na COCI natjecanju zadatak je bio znatno teži: rezovi su smjeli “preskakati”


vertikalne dijelove, tj. nisu morali rezati samo uzastopne dijelove. Koliki je
tada najmanji mogući broj rezova? Najprije razmislite sami, a tek onda
čitajte dalje.

Tražimo dakle broj različitih visina na kojima nešto valja rezati. Ponovno, na
trenutnom vertikalnom dijelu, koji valja razrezati na T komada, tražimo broj
rezova koje možemo produljiti s nekog od prethodnih vertikalnih dijelova.
Visine koje nas zanimaju su 1/T, 2/T, …, (T - 1)/T.

Kada su ovi razlomci do kraja skraćeni, u nazivnicima su djelitelji broja T. Za


svaki takav djelitelj d javljaju se razlomci oblika x/d, gdje su (x, d) relativno
prosti jer je razlomak do kraja skraćen. Je li se rez x/d prije pojavio? Jest,
ako je on jednak y/T’ za neki prijašnji broj komada T’, što znači da je T’
višekratnik od d. Ako smo za sve prethodne T’ označili njihove djelitelje d’
kao iskorištene (npr. koristeći niz nula i jedinica), lako je provjeriti nalazi li
se d među njima.

Postupak je dakle sljedeći: za svaki djelitelj d broja T (djelitelje tražimo u


složenosti O(sqrt(T))) provjeravamo je li već iskorišten, tj. postoje li rezovi
x/d. Ako ne, označavamo ga iskorištenim i rješenju pribrajamo sve rezove
x/d: tražimo dakle broj x-eva manjih od d i relativno prostih sa d, a to je
Eulerova funkcija broja d čije ćemo vrijednosti izračunati unaprijed koristeći
formule za Eulerovu funkciju.
Potrebno znanje: matematička analiza problema, Euklidov algoritam

Kategorija: matematika

HONI 2013/2014 Zadatak GMO


1. kolo, 22. listopada 2012. Autor: Adrian Satja Kurdija

Zadatak je moguće riješiti dinamičkim programiranjem, za što na prvi pogled


manjka memorije. Razradu takvog rješenja za sve bodove ostavljamo
čitateljici za vježbu, a ovdje opisujemo jednostavnije rješenje.

For-petljom odabiremo mjesto početka traženog svinjskoga gena u DNK nizu


jabuke. Potom, unutarnjom petljom, gradimo taj gen od odabranog početka
na prirodan način: ako je sljedeći znak jabuke jednak sljedećem znaku
svinjskoga gena koji trebamo postići, prelazimo na sljedeći znak; inače
moramo ubaciti znak koji želimo postići. Nikad se ne isplati ubaciti znak ako
ga ne moramo ubaciti. Zato će ovaj (pohlepni) algoritam dati najbolju
ukupnu cijenu za odabrani početak. Konačno je rješenje minimum ovih
cijena za sve moguće početke.

Potrebno znanje: pohlepni algoritmi ili dinamičko programiranje

Kategorija: ad hoc

HONI 2013/2014 Zadatak SUMO


1. kolo, 22. listopada 2012. Autor: Adrian Satja Kurdija

Najprije moramo znati odgovoriti na sljedeće pitanje. Za neki broj K, je li


moguće podijeliti borce u dvije ekipe tako da u prvih K borbi ne bude
sučeljavanja boraca iste ekipe?

Zapravo treba provjeriti je li graf koji čini N vrhova (koji predstavljaju borce)
i K bridova (koji predstavljaju borbe) bipartitan, tj. je li njegove vrhove
moguće obojiti dvjema bojama tako da su susjedni vrhovi uvijek različitih
boja. To provjeravamo tako da vrhove zaista bojimo: krećemo od vrha 1,
bojimo ga u bijelo, potom njegove susjede bojimo u crno (jer moramo),
potom susjede ovih susjeda bojimo u bijelo (jer moramo) i tako dalje.
Ovakvo bojenje provodimo BFS ili DFS algoritmom. Algoritam završava kad
smo uspješno obojili sve komponente grafa, što znači da je bojenje moguće,
ili kad smo došli u kontradikciju: neki susjed vrha X iz kojeg se trenutno
širimo već je obojen u istu boju kao X, što znači da bojenje nije moguće.
Sad je jasno da tražimo najmanji K za koji će opisana provjera reći da
podjela ne postoji. Iskušavanje svih mogućih K presporo je. Zato traženu
vrijednost broja K pronalazimo binarnim pretraživanjem.

Potrebno znanje: binarno pretraživanje, širenje na grafu

Kategorija: grafovi

HONI 2013/2014 Zadatak ČOKOLADE


1. kolo, 22. listopada 2012. Autor: Marin Tomić

Zadatak ćemo protumačiti na ovaj način: za neki niz brojeva duljine N,


potrebno je za svaki x od 1 do N odrediti koji je najmanji broj kojim je
potrebno cjelobrojno podijeliti sve članove niza tako da bismo imali skupinu
od točno x jednakih brojeva u nizu ili reći da takav broj ne postoji. Ako s V
označimo najveći broj u nizu, jasno je da će sva rješenja ležati u intervalu
[1, V+1].

Tako dolazimo do prvog rješenja složenosti O(N*V). Za svaki broj x u


intervalu [1, V+1] jednostavnim prolaskom i pamćenjem brojača u polju
možemo odrediti koliko brojeva daje koji količnik pri dijeljenju s x te
obnavljati polje rješenja u skladu s tim.

Za rješenje koje donosi sve bodove, potrebno je moći brže izračunati koliko
brojeva daje neki količnik pri dijeljenju brojem x.

Uočavamo sljedeće:
brojevi koji pri cjelobrojnom dijeljenju s x daju 0 su svi brojevi iz
intervala [0, x-1]
brojevi koji pri cjelobrojnom dijeljenju s x daju 1 su svi brojevi iz
intervala [x, 2x-1]
općenito, brojevi koji pri cjelobrojnom dijeljenju s x daju k su svi
brojevi iz intervala [kx, (k+1)x-1]

Ako možemo napraviti strukturu koja može brzo odgovarati na pitanje koliko
brojeva iz niza leži u intervalu [a, b] možemo brzo odrediti koliko brojeva
daje količnik k pri dijeljenju s x. Budući da su brojevi iz niza veličine do 106
struktura će zapravo biti jednostavni niz A[] u kojem na mjestu A[t] piše
koliko ima brojeva manjih od t. Sada broj brojeva iz niza koji leže u intervalu
[a, b] računamo po formuli A[b] - A[a - 1].

Najveći količnik k koji možemo dobiti za neki x iznosi V/x. Zato je potrebno
napraviti V/x + 1 upita da bismo odredili koliko ima brojeva koji daju
količnik 0, 1, 2, … V/x pri dijeljenju s x. Budući da za x moramo isprobati
sve brojeve od 1 do V+1 to je ukupno (V/1 + V/2 + V/3 + … + V/(V+1))
upita. Dakle, složenost ovakvog algoritma je O(V lg V).

Na COCI-ju se pojavio zadatak s nešto drukčijim ograničenjima: N ≤ 100, V


≤ 108. Ova verzija zadatka traži drukčiji pristup rješenju.

Za svaki broj K u nizu promatrajmo sljedeći niz: [K/1], [K/2], [K/3], …,


[K/K], [K/(K+1)], pri čemu [.] označava najveće cijelo. Možemo primijetiti
da će se taj niz sastojati od blokova uzastopnih jednakih vrijednosti. Brojeve
i za koje je [K/i] različito od [K/(i-1)] nazvat ćemo bitnim brojevima.

Sada možemo raditi algoritam sličan početnom rješenju složenosti O(N*V),


samo što ne moramo isprobati sve x-eve od 1 do V+1, nego nam je
dovoljno provjeriti samo bitne brojeve za sve K koje imamo u nizu jer će za
nebitne x svi količnici bit jednaki kao za neki bitan x.

Sada je složenost O(N * ukupan broj bitnih brojeva * lg N). Može se


pokazati da za broj K postoji najviše različitih bitnih brojeva, tako da je
ukupna složenost O(N * N * lg N).

Za implementacijske detalje pogledajte izvorne kodove.

Potrebno znanje: matematička analiza problema, preprocessing

Kategorija: matematika

HONI 2013/2014 Zadatak UTRKA


1. kolo, 22. listopada 2012. Autor: Goran Žužić

Označimo s Mab(k) najveću prednost koju Mirko može ostvariti na ruti od


najviše k koraka koja počinje u zaselku a te završava u zaselku b. Zadatak
traži da pronađemo najmanji kmin takav da je jedan dijagonalni element
matrice M(kmin) strogo pozitivan (te nas, kao drugi broj na izlazu, zanima i
najveći takav dijagonalni element matrice M(kmin)).

Primijetimo da ako znamo M(p) i M(q), možemo postupkom sličnim množenju


matrica izračunati i M(p+q). Složenost je postupka O(N3).

Gornje observacije dopuštaju nam da iskoristimo binarno pretraživanje po k,


te potom korištenjem brzog (matričnog) potenciranja izračunamo M(k).
Nažalost, složenost takvog postupka je O(N3 log2 N), što je nosilo nešto
manje od 100% bodova.

Za pune bodove bilo je potrebno izračunati matrice M(k) za k = 20, 21, 22, …
(složenost O(N3 log N)) te potom odrediti minimalni k u postupku koji mu
određuje jednu po jednu znamenku u binarnom zapisu (od najjače prema
najslabijoj). Ukupna složenost postupka još uvijek je O(N3 log N) što je bilo
dostatno za 100% bodova na zadatku.

Potrebno znanje: min+ množenje matrica

Kategorija: grafovi

You might also like