You are on page 1of 5

HONI 2016/2017

5. kolo, 21. siječnja 2017.

Opisi algoritama
Zadatak Klizanje Autor: Marija Gegić

Najprije je potrebno uočiti da Mirko raspolaže s ukupno N+M karata, a na klizanje će doći
ukupno A+B ljudi. U slučaju kad na klizanje dođe više ljudi nego što Mirko ima karata, on će
prodati sve karte koje ima. U slučaju kad na klizanje dođe manje ljudi nego što Mirko ima
karata, on će svakoj osobi koja je došla prodati jednu kartu, pa će ukupan broj prodanih
karata biti jednak broju osoba koje su došle na klizanje. Dakle, traženo rješenje je manji od
brojeva (N+M) i (A+B).

Potrebna znanja: ​višestruka if provjera, if-else konstrukcija


Kategorija:​ ad-hoc

Zadatak Ostatak Autor: Adrian Satja Kurdija

For petljom isprobavamo sve mogućnosti za X od 1 nadalje. Kada pronađemo X za koji


vrijedi X * K % D == O, on je traženo rješenje pa ga ispisujemo i prekidamo petlju.

Kada ćemo zaključiti da nema rješenja? Primijetite da se ostatci pri dijeljenju sa D periodički
ponavljaju s periodom D (a možda i manjim). To znači da je ostatak za X = 1 jednak ostatku
za X = D + 1, ostatak za X = 2 jednak ostatku za X = D + 2 i tako dalje. Iz toga slijedi da, ako
se zadani ostatak O nije pojavio za X = 1, 2, …, D, tada se uopće neće pojaviti pa u tom
slučaju nema rješenja.

Potrebna znanja:​ ​for petlja


Kategorija:​ ad-hoc

Zadatak Tuna Autor: Nikola Dmitrović

Učitavanje ulaznih podataka jedini je problem u ovom zadatku. U slučaju da je apsolutna


vrijednost razlike dva ulazna podatka koji se nalaze u istom retku manja ili jednaka od X tada
ukupnu cijenu uvećamo za veći od ta dva broja. Ako je razlika strogo veća od X znamo da
ćemo u sljedećem retku dobiti još jedan ulazni podatak koji onda samo trebamo dodatno
učitati i dodati na ukupnu cijenu. Opisani algoritam ponovimo N puta.

Potrebna znanja:​ učitavanje podataka, naredba odlučivanja, for petlja, određivanje većeg
od dva broja
Kategorija:​ ad-hoc

Zadatak Pareto Autor: Adrian Satja Kurdija


Sortirat ćemo iznose po veličini silazno, od najvećeg do najmanjeg. Za svaki “prefiks” koji se
sastoji od K najbogatijih klijenata izračunat ćemo odgovarajuće brojeve A i B, tj. udio tog
prefiksa u broju računa (A = K / N * 100%) te udio ukupnog novca koji zauzima taj prefiks: B
= (zbroj najvećih K iznosa) / (zbroj svih iznosa) * 100%. Tada provjerimo je li razlika B - A
​ veća od dosad najveće pronađene: ako jest, ažuriramo pomoćne varijable A ​ _best, ​B_best
koje na kraju ispisujemo.

Zbog veličine niza potrebno je efikasno sortirati, u složenosti O(N log N), te efikasno računati
zbroj prefiksa, što je najjednostavnije učiniti tako da zbroj K-prefiksa računamo dodajući K-ti
element na prethodno izračunati zbroj (K-1)-prefiksa.

Potrebna znanja:​ sortiranje


Kategorija:​ ad-hoc

Zadatak Unija Autor: Adrian Satja Kurdija

Dovoljno je promatrati samo desnu polovinu slike i na kraju rezultat udvostručiti. Rješenje je
zbrojiti visine X-stupaca za X = 1, 2, …, 10^7, što možemo učiniti ​for petljom.

Kako odrediti visinu stupca na koordinati X? Ona je veća ili jednaka visini stupca na
koordinati X + 1. Veća je ako postoji pravokutnik koji završava na koordinati X i viši je od
stupca na koordinati X + 1, a inače je jednaka. Zato na početku treba zapisati na kojiim
X-koordinatama završavaju dani pravokutnici i koje su visine, te prolaziti X-stupce “unatrag”,
prema ishodištu, da bismo mogli primijeniti formulu iz prethodne rečenice.

Potrebna znanja:​ nizovi


Kategorija:​ ad-hoc

Zadatak Ronald Autor: Adrian Satja Kurdija

Za bilo koju liniju A-B zaključujemo: svakim Krumpovim odabirom grada A ili grada B mijenja
se njezino postojanje, pa njezino konačno postojanje ovisi samo o parnosti broja odabira
gradova A i B. Budući da su, dakle, važne samo parnosti broja odabira pojedinih gradova,
dovoljno je pretpostaviti da Krump svaki grad bira nula ili jedan put (odabir ili ne-odabir), što
bitno pojednostavljuje zadatak.

Promatramo dvije mogućnosti: Krump odabire ili ne odabire grad 1. Za svaku od ovih
mogućnosti provjerit ćemo može li dovesti do potpunosti grafa. Ako smo fiksirali odabir (ili
ne-odabir) grada 1, za bilo koji drugi grad K možemo lako zaključiti mora li biti odabran s
obzirom na parnost koja mora omogućiti postojanje linije 1-K. Na taj način određujemo
odabire ili ne-odabire svih gradova od 2 do N. Budući da smo ovako osigurali samo
postojanja linija 1-K, provjerit ćemo postojanja svih ostalih linija i ako one sve postoje,
imamo odgovor DA.

Alternativno je rješenje sljedeće: odgovor je DA ako i samo ako se početni graf sastoji od
točno dvije komponente od kojih je svaka potpuni graf (klika). Dokaz ostavljamo čitateljima
za vježbu.

Potrebna znanja:​ zaključivanje


Kategorija:​ grafovi

Zadatak Poklon Autor: Dominik Gleich

Zadatak ćemo rješavati offline metodom, gdje ćemo prvo učitati sve upite, a zatim ih
obrađivati. Za početak, definirajmo dvije funkcije, left(x), right(x) koje odgovaraju poziciji
prvog lijevog, tj. prvog desnog elementa iste vrijednosti onom na poziciji x. Te dvije funkcije
nije teško izračunati krećući se s lijeva na desno, odnosno s desna na lijevo prateći ‘zadnje’
svake vrijednosti koristeći hash mapu, strukturu Map u C++-u ili obično polje ukoliko najprije
napravimo sažimanje vrijednosti. Promatrajmo neki upit [L, R] i funkcije left(x), right(x). Nije
teško za primijetiti da ćemo neku poziciju x ubrojati u upit [L, R] ukoliko je left(x) < L <= x <=
right(x) <= R < right(right(x). Prirodnim jezikom: želimo da se prvo lijevo pojavljivanje
vrijednosti nalazi prije lijevog kraja intervala, a prvo desno pojavljivanje prije ili na desnom
kraju intervala uz to da ne postoji još jedno pojavljivanje vrijednosti u intervalu. Time
osiguravamo prebrojavanje svakog para dvije iste vrijednosti točno jednom. Time svodimo
zadatak na sljedeći problem: za neki ​x​ povećaj za jedan rješenje svakog upita gdje je left(​x​)
< L <= ​x​ i gdje je right(​x​) <= R < right(right(​x​)).

Kako bismo izveli ovaj upit potrebno je konstruirati tournament strukturu podataka nad svim
intervalima na sljedeći način: za svaki čvor tournamenta koji pokriva interval [A, B] potrebno
je ‘ubaciti’ upit [L, R], ako je A <= L <= R, tj. L e [A, B]. Nakon ovog, potrebno je za svaki ​x​,
ubaciti interval [right(​x​), right(right(​x​))> u sve čvorove stabla od kojih je interval <left(​x​), ​x​]
sačinjen (klasična query ili update operacija nad tournametnom). Takvih čvorova ima O(lg N)
za svaki ​x​. Nakon ubacivanja upita i intervala u tournament, potrebno je za svaki čvor stabla
izračunati ‘prinos’ upitima koji se nalaze u tom čvoru, taj dio odrađujemo sweep tehnikom i
ostavljamo čitatelju detalje implementacije kao vježbu.

Ukupna složenost priloženog rješenja je O(N lg​2​ N). Također postoji i rješenje složenosti O(N
lg N), koje također ostavljamo čitatelju za vježbu.

Potrebna znanja:​ sweep, strukture podataka


Kategorija:​ tournament, strukture podataka

Zadatak Strelice Autor: Mislav Balunović


Napravimo graf čiji čvorovi su polja ploče, a bridove dobijemo tako da za svaku strelicu na
ploči koja nije u posljednjem stupcu povežemo odgovarajuća dva čvora usmjerenim bridom.
Budući da svaki čvor ima izlazni stupanj najviše 1, graf koji smo dobili sastoji se od
komponenata koje su 2 različita tipa:
● Usmjereno stablo
● Ciklus sa “granama” koje vode u njega

Svaki put od prvog stupca do zadnjeg stupca zapravo je put od nekog čvora u nekom stablu
do korijena istog tog stabla. Nazovimo čvorove u prvom stupcu “posebnima”. Sada je
zadatak zapravo bojanje točno K čvorova stabla tako da na svakom putu od posebnog čvora
do korijena bude točno jedan obojan čvor.
Primjenimo jedan trik, dodajmo u graf jedan pomoćni čvor i dodajmo brid iz svakog korijena
u taj pomoćni čvor. Sada imamo točno 1 stablo u grafu i za njega rješenje provjeravamo
dinamičkim programiranjem.

Računamo vrijednost funkcije f(x, i, k) koja nam vraća možemo li obojati sva podstabla čvora
x od njegovog i-tog djeteta nadalje. Ključni dio je određivanje koliko ćemo čvorova bojati u
i-tom podstablu. Ako bojamo točno y čvorova onda rješenje postoji ako su vrijednosti obje
f(x, i + 1, k - y) i f(dijete[x][i], 0, y) jednake 1.
Na kraju, pazimo da u komponentama koje vode u cikluse možemo čvorove bojati
proizvoljno.
Ako iteriramo po svim mogućim y složenost algoritma je O(NMK​2​).

Kako bismo ubrzali rješenje, možemo se poslužiti bitmaskama.


Naime, označimo sa F[x][i] bitmasku koja na k-tom mjestu ima bit f(x,i+1,k). Također, sa
R[x][i] označimo istu tu masku koja ima prvih 50 bitova okrenuto (0-ti bit u F je 50-ti u R).
Sada je f(x,i,k) = (R[x][i] >> (50 - k)) & F[dijete[x][i]]. Ostavljamo čitatelju za vježbu da se
uvjeri u točnost ove optimzacije koja omogućava ubrzanje spomenute dinamike na O(NMK).

Potrebna znanja: ​dinamičko programiranje, bitmaske


Kategorija: ​dinamičko programiranje

You might also like