rjesenja

10
HRVATSKO OTVORENO NATJECANJE IZ INFORMATIKE 2013/2014 1. KOLO OPISI ALGORITAMA

description

Solutions

Transcript of rjesenja

HRVATSKO OTVORENO NATJECANJE IZINFORMATIKE

2013/2014

1. KOLO

OPISI ALGORITAMA

HONI 2013/2014 Zadatak GLEDATELJ1. kolo, 28. rujna 2013. Autor: Marin Tomić

Jednostavan zadatak za zagrijavanje. Potrebno je pronaći jednostavnuformulu za broj bodova koju je pojedina ekipa osvojila:3 * T + 2 * D + S, pri čemu je T broj „trica“, D broj „dvica“, a S brojslobodnjaka.

Potrebno znanje: množenje i zbrajanje, učitavanje i ispisivanje

Kategorija: matematika, sport

HONI 2013/2014 Zadatak PRODAVAČ1. kolo, 28. rujna 2013. Autor: Marin Tomić

Ovaj zadatak može se riješiti tako da napišemo 61 uvjet, po jedan zasvaki dan prvenstva. Naravno, poželjno je to izbjeći koristećielegantniji pristup poput ovog:

svakom danu prvenstva dodijelimo redni broj, 1. listopadadobiva broj 1, a 30. studenog dobiva broj 61

sada je dovoljno gledati ostatak rednog broja pri dijeljenju sa 7.Lako je primijetiti da utorak „pada“ na dane s rednim brojem kojidaje ostatak 1, srijeda na dane s rednim brojem koji dajeostatak 2, ...

Tako možemo zadatak riješiti sa samo 7 uvjeta, umjesto 61. Dakako,ne smijemo izostaviti dodatna 2 uvjeta za dane kada Mirko prodaje„zanimaciju“.

Potrebno znanje: grananje(if-then), matematika

Kategorija: ad-hoc

HONI 2013/2014 Zadatak TRENER1. kolo, 28. rujna 2013. Autor: Marin Tomić

Potrebno je prebrojati koja slova se u ulazu pojavljuju barem 5 putakao početno slovo prezimena. To se može napraviti tako da se zavrijeme učitavanja u jednom nizu veličine 26 broji koliko puta se kojeslovo pojavilo. Nakon učitavanja dovoljno je jednom proći kroz niz iispisati ona slova koja se pojavljuju barem 5 puta. Također trebapripaziti i ispisati „PREDAJA“ u slučaju da nije ispisano nijedno slovo.

Za implementacijske detalje pogledajte izvorni kod.

Potrebno znanje: nizovi, for-petlja, stringovi

Kategorija: ad-hoc

HONI 2013/2014 Zadatak KUŠAČ1. kolo, 28. rujna 2013. Autor: Adrian Satja Kurdija

Optimalnom strategijom rezanja pokazuje se sljedeća. Poredajmokobasice u dužinu, jednu za drugom. (Dobivena dužina sastoji se od Nmanjih dužina.) Tu dužinu prerežimo na M jednakih dijelova: to će bititraženo rezanje.

Od načinjenih M - 1 rezova nisu svi pravi rezovi: neki se od njihpodudaraju s rubovima kobasica (manjih dužina), tj. prolaze izmeđukobasica. Primjerice, ako su dvije kobasice a četiri kušača, prvi rez bitće pravi i rezat će prvu kobasicu na pola, drugi rez neće biti pravi (jerće prolaziti točno između dviju kobasica), a treći rez bit će pravi i rezatće drugu kobasicu na pola.

Valja nam dakle prebrojati “rubne” rezove. Ako je K-ti rez rubni, značida je prvih K od M dijelova velike dužine jednako prvih X kobasica,gdje je X cijeli broj. Drugim riječima, (K / M) od N kobasica iznosi Xkobasica. Drugim riječima, X = (K * N) / M. Sad je jasno da će X biticijeli broj (a rez biti rubni) ako je K * N djeljiv s M. Sada for-petljomza svaki mogući K (od 1 do M - 1) na ovaj način lako provjeravamoradi li se o pravom ili rubnom rezu.

Alternativno, moguće je izvesti i eksplicitnu formulu: rješenje = M -nzd(N, M). Dokaz ostavljamo čitateljici za vježbu.

Potrebno znanje: for-petlja, množenje cijelog broja razlomkom

Kategorija: ad hoc

HONI 2013/2014 Zadatak RATAR1. kolo, 28. rujna 2013. Autor: Matija Bucić

Prvi korak ka uspješnom rješavanju ovog zadatka je pronalaženjenačina kako brzo izračunati ukupnu dobit nekog pravokutnika. Dobarnačin za to slijedi...

Unaprijed ćemo izračunati (preprocessati) N * N matricu P gdjeP[x][y] označava sumu vrijednosti u pravokutniku sa nasuprotnimvrhovima (0, 0) te (x, y). Za potrebe ovog zadatka izračunavanjevrijednosti svih takvih pravokutnika dovoljno je izvesti u složenostiO(N4) prolaženjem kroz cijeli pravokutnik svaki put pri računanju.Naravno, to je moguće napraviti i u složenosti O(N2) što ostavljamočitateljici za vježbu.

Ovaj postupak je koristan jer sada možemo odrediti ukupnu dobit bilokojeg pravokutnika u složenosti O(1) umjesto u složenosti O(N2)koristeći formulu uključivanja i isključivanja:

suma(x1, y1, x2, y2) = P[x2][y2]+P[x1 - 1][y1 - 1]-P[x1 - 1, y2]-P[x2][y1 - 1]

Jednostavan način za prebrojati valjane parove pravokutnika jeisprobavanje svake četvorke točaka kao moguće nasuprotne vrhove iprovjeravanje imaju li zajedničku točku i imaju li istu sumu koristećigornju formulu. Složenost takvog rješenja je O(N8) i vrijedi 20%bodova.

Gornje rješenje možemo jednostavno optimizirati tako da neisprobavamo svaku četvorku točaka kao nasuprotne vrhove, negofiksiramo zajedničku točku pravokutnicima, čime smo odredili po jedanvrh svakom pravokutniku. Sada nam preostaje fiksirati preostala dvavrha svakom pravokutniku i napraviti potrebne provjere. Tako sesloženost smanjuje na O(N6) i dobiva 40% bodova.

Za posljednju optimizaciju potrebno je iskoristiti činjenicu da su dobitijediničnih kvadratića brojevi između -1000 i 1000 što znači da je

ukupna dobit svakog pravokutnika između -1000 * N2 i 1000 * N2.Budući da je N najviše 50, možemo napraviti polje veličine 2000 * N2

u kojem brojimo koliko imamo pravokutnika s kojom ukupno dobiti.

Recimo da prebrojavamo parove pravokutnika koji se dodiruju u donjojlijevoj i gornjoj desnoj točki (kao na slici). Fiksiramo zajedničku točkupravokutnika na sve moguće načine. Odabiremo gornji lijevi vrhpravokutnika broj 1 na sve moguće načine i brojimo u polju kolikoimamo pravokutnika sa kojom sumom. Nakon toga odabiremo donjidesni vrh pravokutnika broj 2 te za svaki pravokutnik određene sumeiz polja očitavamo koliko ima odgovarajućih gornjih lijevihpravokutnika i pribrajamo to u rješenje. Isto ponavljamo zapravokutnike kojima je zajednički vrh donja lijeva i gornja desnatočka.

Složenost gornjeg algoritma je O(N4) i on nosi 100% bodova. Zaimplementacijske detalje pogledajte izvorni kod.

Potrebno znanje: korištenje pomoćnih nizova, preprocessing,baratanje dvodimenzionalnim nizovima (matricama)

Kategorija: ad-hoc

HONI 2013/2014 Zadatak LOPOV1. kolo, 28. rujna 2013. Autor: Domagoj Ćevid

Zadatak se rješava jednostavnim pohlepnim algoritmom. Sortiramokomade nakita po cijeni. Zatim krećemo od najskupljeg komada premanajjeftinijem i radimo sljedeće:

ako postoji, uzmi najmanju vreću čija je nosivost veća od težinetrenutnog komada nakita. Izbaci tu vreću iz skupa vreća ipridodaj cijenu trenutnog komada u rješenje

ako ne postoji takva vreća, preskoči ovaj komad nakita i nastavidalje

Za implementaciju ovog algoritma potrebna je struktura podataka kojapodržava tri operacije: ubaci broj, nađi prvi broj veći od nekog broja xili javi da ne postoji, izbaci neki broj. Oni koji programiraju u C++mogu iskoristiti gotovu strukturu - multiset.

Programeri u Pascalu će se morati malo više namučiti za ovaj zadatak.Za njih je jednostavnije implementirati sljedeći algoritam čija je glavnaideja u osnovi vrlo slična kao i u gore navedenom.

Za razliku od gornjeg algoritma gdje je potrebno balansirano binarnostablo ili logaritamska struktura, za ovaj algoritam je potrebnosortiranje i binarni heap što je donekle lakše implementirati.

Binarni heap je struktura koja podržava tri operacije: ubaci broj, recikoji je najveći broj, izbaci najveći broj.

Algoritam je sljedeći: sortiraj nakit i vreće po težini zajedno u jedan niz kreni od predmeta najmanje težine prema predmetu najveće

težine kada naiđeš na komad nakita, ubaci njegovu vrijednost u heap kada naiđeš na vreću, ako heap nije prazan, uzmi najskuplji

komad nakita na koji si naišao do sad (on će sigurno imati manjutežinu zbog načina na koji smo sortirali) i izbaci ga iz heapa.Njegovu vrijednost pribroji u trenutno rješenje.

Dokaz gornjih algoritama ostavljamo čitateljici za vježbu.

Potrebno znanje: heap ili multiset, pohlepni algoritmi

Kategorija: ad-hoc

HONI 2013/2014 Zadatak ORGANIZATOR1. kolo, 28. rujna 2013. Autor: Domagoj Ćevid

Primijetimo da je rješenje veličina tima * broj klubova koji mogusudjelovati, a sudjelovati mogu svi klubovi kojima je broj članovadjeljiv s veličinom tima.

Najjednostavniji način za prebrojati broj klubova koji mogu sudjelovatiza veličinu tima V jest da prođemo kroz cijeli niz sa veličinama klubovai brojimo koliko je klubova djeljivo. Složenost ovog algoritma jeO(maxV * N) pri čemu je maxV najveća moguća veličina kluba jerveličina tima može poprimiti sve vrijednosti od 1 do maxV, a za svakuprovjeru nam je potrebno N koraka.Potrebno je pronaći bolju metodu za računanje koliko ima ekipa kojese mogu natjecati. Budući da su veličine ekipa brojevi do 2 milijuna,možemo napraviti niz a veličine maxV u kojem će na i-tom mjestupisati koliko ima ekipa sa i članova.

Da bi izračunali koliko ima ekipa koje mogu sudjelovati ako je veličinatima d, potrebno je izračunati sumu: a[d] + a[2 * d] + a[3 * d] + ...,za što je potrebno maxV / d koraka.

Za isprobavanje svih mogućnosti od 1 do maxV kao broj d potrebnoje: maxV / 1 + maxV / 2 + maxV / 3 + ... + maxv / (maxV-1) + 1koraka što je otprilike maxV lg maxV. Složenost ovog algoritma jeO(maxV lg maxV) što je dovoljno brzo za osvojiti sve bodove.

Potrebno znanje: baratanje s nizovima, izračunavanje složenosti

Kategorija: ad-hoc

HONI 2013/2014 Zadatak SLASTIČAR1. kolo, 28. rujna 2013. Autor: Marin Tomić

Riješimo prvo jednostavniju verziju zadatka u kojoj robot ne stajenakon što pronađe traženi serijski broj nego uvijek isproba svih Nsegmenata.

Neka je f(W, S) broj sufiksa stringa S koji imaju prefiks W. Neka jeS[x..y] oznaka za podstring stringa S od mjesta x do mjesta y.

Tada je broj usporedbi koje će robot napraviti za riječ W duljine L:BS + f(W[1..1], S) + f(W[1..2], S) + ... + f(W[1..i], S) + ... + f(W[1..L], S),pri čemu je BS ukupan broj segmenata s kojima je robot započeousporedbu. U ovoj pojednostavljenoj verziji zadatka, BS je uvijek N,jer robot ne staje s usporedbama kad pronađe riječ.

Potreban nam je efikasan način kako izračunati funkciju f(W, S). Tomožemo napraviti tako da napravimo suffix array stringa S. Suffixarray je skup svih sufiksa stringa S sortiranih u leksikografskomporetku. Sada binarnim pretraživanjem možemo u suffix arrayupronaći interval sufiksa koji počinju na slovo W[1]. Neka je taj interval[l1, r1]. Funkcija f(W[1..1], S) je tada r1 - l1 + 1. Zatim unutar togintervala pronalazimo interval sufiksa kojima je drugo slovo W[2], [l2,r2]. f(W[1..2], S) je r2 - l1 + 1. Postupak dalje postavljamo na istinačin za sva slova stringa W.

Složenost ove pretrage je O(L lg N) što je dovoljno brzo jer sumaduljina svih upita neće biti veća od 3 000 000.

Što kada robot staje kada prvi put naiđe na riječ?

Za sve riječi ćemo izračunati prvo mjesto na kojima se pojavljuju, pi.Neka je g(W, S, p) funkcija koja kaže koliko ima sufiksa stringa S saprefiksom W koji počinju zaključno sa pozicijom p. Sada možemoizvesti novu formulu za ukupan broj usporedbi:BS + g(W[1..1], S, pi) + ... + g(W[1..L], S, pi),s time da je BS sada pi jer nakon te pozicije stajemo s usporedbama.

Kako bi olakšali računanje funkcije g, nećemo odgovarati na upite uredoslijedu kojim su nam dani u ulaznim podacima, nego ćemo ihsortirati na način koji nama odgovara i odgovore spremiti u jedan niz.Kada izračunamo sve odgovore ispisat ćemo ih u odgovarajućemporetku.

Upite ćemo sortirati uzlazno po pi. Također ćemo napraviti strukturukoja podržava dvije operacije: dodaj 1 na neko mjesto, odgovori kojaje suma brojeva u nekom intervalu. Ta struktura će nam omogućiti daračunamo koliko ima trenutno bitnih prefiksa u nekom intervalu.Možemo je implementirati pomoću logaritamske strukture ilitournament stabla.

Upite rješavamo na sljedeći način: recimo da trenutno odgovaramo na upit koji je pronađen na

mjestu pi u strukturi na odgovarajuća mjesta za sve sufikse do pi

postavljamo jedinice. Valja primijetiti da ne moramo uvijekisponova postavljati jedinice od prvog sufiksa nego samo odsufiksa na kojem smo stali u prošlom upitu jer su upiti sortiranipo pi.

na isti način kao i u lakšoj verziji zadatka pronalazimointervale [l1, r1], [l2, r2], ..., [lL, rL]. Sada u odgovor nedodajemo ri - li + 1 već sumu intervala [li, ri] u strukturi. Tasuma je zapravo odgovor na pitanje koliko ima sufiksa kojipočinju do mjesta pi u intervalu [li, ri] u sufix arrayu.

izračunati odgovor spremamo u niz sa odgovorima naodgovarajuće mjesto

Na kraju programa ispišemo niz s odgovorima.

Još je jedna sitnica ostala nerazriješena, kako pronaći brojeve pi?Nakon što za neku riječ W pronađemo posljednji interval [lL, rL] znamoda svi sufiksi iz tog intervala imaju prefiks W. Prvo mjesto gdje sepojavljuje je početno mjesto najlijevijeg od tih sufiksa, tj. sufiks snajmanjim indeksom. Dakle, moramo napraviti strukturu koja će moćiodgovoriti koji je najmanji broj u nekom intervalu. To možemonapraviti uz pomoć tournament stabla ili sličnih struktura.

Za implementacijske detalje pogledajte izvorni kod.

Postoje razni algoritmi za izgradnju suffix arraya u raznimsloženostima koji se mogu pronaći na internetu. U službenom rješenjuimplemetiran je algoritam složenosti O(N lg2 N).Također, u službenom rješenju su implementirani tournament ilogaritamska struktura. Složenost svakog upita u tim strukturama jeO(lg N).

Ukupna složenost algoritma je O(N lg2 N + suma duljina upita * lg N).

Potrebno znanje: napredne strukture podataka (suffix array,tournament, logaritamska), binarno pretraživanje

Kategorija: stringovi, strukture podataka