You are on page 1of 12

HRVATSKO OTVORENO NATJECANJE IZ

INFORMATIKE

2. KOLO

RJEŠENJA
HONI 2010/11 Zadatak PUŽ

2. kolo, 13. studeni 2010. Autor: Stjepan Glavina

Simulacija penjanja i spuštanja dok puž ne stigne do vrha je prespora, budući da


rezultat može biti jako velik broj.

Nakon jednog dana i jedne noći puž se ukupno popne za A - B metara. On se prvo
penje i spušta X dana i X noći, a onda nakon toga u jednom danu dosegne vrh
štapa. Zato je potrebno naći najmanji X za kojeg vrijedi X * (A - B) + A ≥ V.

Rješenje:

Rješavamo nejednakost na ovaj način:


X * (A - B) + A ≥ V
X * (A - B) ≥ V - A
X = ⌈(V - A) / (A - B)⌈
X = ⌈(V - A + A - B - 1) / (A - B)⌈
X = ⌈(V - B - 1) / (A - B)⌈

Sada možemo direktno izračunati X koristeći cjelobrojno dijeljenje.


Rezultat koji treba ispisati je X + 1.

Alternativno rješenje:

Umjesto rješavanja nejednakosti, možemo koristiti binarno pretraživanje da bismo


našli najmanji X za kojeg vrijedi nejednakost. Binarno pretraživanje je tehnika
pogañanja: probamo neki X i onda provjerimo jesmo li pogodili broj. Ako nismo
pogodili, onda gledamo je li broj prevelik ili premalen. Dovoljno nam je samo oko
log2 V pogañanja pa algoritam ima složenost O( log V ).

Potrebno znanje:

Rješavanje nejednakosti, binarno pretraživanje

Kategorija

Matematika, binarno pretraživanje


HONI 2010/11 Zadatak NAPOR

2. kolo, 13. studeni 2010. Autor: Matija Osrečki

Kako bi se zadatak uspješno riješio, potrebno je riješiti dva potproblema - prvo


treba pronaći sve brojeve u tekstu, odnosno parsirati tekst, a onda treba sortirati te
brojeve.

Parsiranje teksta:

Ključna stvar koju treba primijetiti prilikom parsiranja niza je da duljina linije može
biti 100, a nema nikakvog ograničenja na veličinu brojeva, zbog čega brojevi mogu
biti preveliki za 64-bitni cjelobrojni tip podataka (long long u jezicima C i C++,
int64 u Pascalu). Upravo zbog toga brojeve treba pamtiti na neki drugi način, od
kojih je najjednostavniji način pamtiti ih kao stringove.

Sad se može krenuti u parsiranje. Tekst se parsira liniju po liniju, a za svaku liniju
je potreban jedan prolaz slijeva na desno kako bi se našli svi brojevi. Osnovna ideja
je slijedeća - liniju čitamo znak po znak, i svaki uzastopni niz brojeva spremamo u
novi string, i kad naletimo na slovo, taj broj spremimo. Kako bi to programski
ostvarili potrebno je sljedeće:
● niz stringova num[] - u njega dodajemo pronañene brojeve
● string X - predstavlja broj koji se trenutno “gradi”
● statusna zastavica S

Algoritam radi na slijedeći način. Kazaljka se kreće slijeva na desno znak po znak. U
svakom koraku radimo sljedeće:
● ako je ispod kazaljke slovo i vrijedi:
⌈ S je 0 - ništa ne radimo
⌈ S je 1 - naletjeli smo na niz nula, i u num[] dodajemo broj 0
⌈ S je 2 - u num[] dodajemo X i X postaje prazan string
⌈ S je 1 ili 2 - još postavljamo zastavicu na 0
● ako je ispod kazaljke znamenka D i vrijedi:
⌈ S je 0 i D je 0 - S postaje 1
⌈ D nije 0 ili je S 2- dodajemo D na kraj X i S postaje 2 (ako već nije)

S nam služi da riješimo problem vodećih nula. Na početku je vrijednost 0. Kad


naletimo na nulu, smijemo ju dodati na kraj X samo ako smo već naletjeli na
znamenku koja nije nula (u tom broju), što objašnjava vrijednost 2. S druge strane
ako imamo samo niz nula, po vrijednosti 1 ćemo znati da smo naletjeli samo na
nule i da treba dodati samo broj 0 (tako izbacujući vodeće nule).
Nakon što se obrade svi znakovi, a na kraju linije je neki broj, treba ga dodati u niz.

Sortiranje velikih brojeva:

Kad smo pronašli sve brojeve, treba ih sortirati. Pošto su brojevi spremljeni kao
stringovi, potreban je poseban način usporeñivanja brojeva. Ako imamo stringove A
i B koji predstavljaju brojeve, njihove veličine se mogu usporediti na slijedeći način:
● ako je duljina stringa A manja od B, A je manji broj od B
● inače nañi najmanji i tako da vrijedi da je A[i] različit od B[i]
⌈ ako je A[i] < B[i], A je manji od B, inače je B manji od A
● ako su stringovi A i B isti, tj. nema takvog i, brojevi A i B su jednaki

Kad imamo funkciju za usporeñivanje, brojeve možemo sortirati primjenom bilo


kojeg algoritma, što bi za najjednostavniji algoritam poput bubble sorta značilo
složenost O(M2 * L), a za neki brži način sortiranja složenost O(log M * L). Pošto je
M (broj brojeva u tekstu) najviše 500, a duljina niza L najviše 100, i sporiji
algoritam će biti dovoljno brz.

Potrebno znanje:

Parsiranje stringova, sortiranje, usporeñivanje velikih brojeva

Kategorija

Parsiranje, sortiranje
HONI 2010/11 Zadatak IGRA

2. kolo, 13. studeni 2010. Autor: Goran Gašić

Primijetimo da, ako Slavko izgubi igru s najljepšom mogućom riječi, on nikako nije
mogao pobijediti. Stoga je dovoljno osmisliti strategiju s kojom će Slavko na kraju
igre imati najljepšu moguću riječ te simulirati igru koristeći tu strategiju.

Primijetimo da je tada nužno da Slavko u svakom potezu uzme neko najmanje


slovo iz niza. U slučaju da uzme neko slovo veće od najmanjega, riječ s kojom će
završiti igru abecedno dolazi poslije najljepše moguće riječi (jer smo na trenutačnu
poziciju mogli staviti manje slovo).

Preostaje odlučiti koje će najmanje slovo Slavko uzeti u svakom potezu. Tvrdim da
će Slavko na kraju igre imati najljepšu moguću riječ ako u svakom potezu od svih
najmanjih slova u nizu odabere najdesnije.

Dokaz:

Neka je Slavko na potezu. Nazovimo najdesnije od svih najmanjih slova u nizu


odabranim slovom. Neka se desno od odabranog slova u nizu nalazi još K
slova. Razmotrit ćemo tri slučaja:

1. Broj najmanjih slova u nizu manji je ili jednak K.

Mirko mora uzeti K slova prije nego što doñe do odabranog slova. Do tada Slavko
može uzeti sva najmanja slova u nizu (jer se desno od odabranog slova ne
nalazi niti jedno takvo). Nebitno je kojim redoslijedom Slavko odabire najmanja
slova pa može uvijek odabrati najdesnije.

2. Broj najmanjih slova u nizu veći je od K i Mirko u sljedećem potezu uzima


odabrano slovo.

Ako Slavko može uzeti sva najmanja slova u nizu, očito sada mora uzeti
odabrano slovo (inače će ga Mirko uzeti).

Ako Slavko ne može uzeti sva najmanja slova u nizu, svejedno je koje najmanje
slovo sada uzme (jer prije ili kasnije mora prepustiti neko najmanje slovo Mirku pa
to može, ali ne mora učiniti sada). Stoga može uzeti odabrano slovo.
3. Broj najmanjih slova u nizu veći je od K i Mirko u sljedećem potezu ne uzima
odabrano slovo.

Pretpostavimo da Slavko u ovome potezu ne uzme odabrano slovo, već neko


drugo. Onda će ga sigurno uzeti najkasnije potez prije nego ga Mirko uzme. Stoga
može zamijeniti ta dva poteza te sada uzeti odabrano slovo, a drugo, koje će i
dalje biti raspoloživo, uzeti kasnije.

Potrebno znanje:

Dokazivanje točnosti pohlepnog algoritma

Kategorija

Pohlepni algoritmi
HONI 2010/11 Zadatak KNJIGE

2. kolo, 13. studeni 2010. Autor: Adrian Satja Kurdija

Treba primijetiti da će optimalan protokol premještanja izgledati ovako: odabrat


ćemo neku knjigu označenu brojem K i stavljat ćemo na vrh redom knjige K, K-1,
K-2, ..., 2, 1. Sljedeća tri odlomka čine dokaz te tvrdnje.

Naime, ako najprije stavimo knjigu broj K na vrh, tada svaku knjigu s manjim
rednim brojem od K sigurno moramo u nekom kasnijem trenutku staviti na vrh, jer
bi u suprotnom ona u konačnom nizu došla nakon knjige broj K.

Takoñer, ako smo u optimalnom protokolu premještanja najprije stavili knjigu broj
K na vrh, neku knjigu s rednim brojem većim od K se nikada ne isplati staviti na
vrh, jer ćemo knjigu broj K onda ponovno morati stavljati na vrh (u suprotnom bi u
konačnom nizu knjiga broj K završila nakon te knjige s većim rednim brojem).
Meñutim, ne isplati se dvaput premještati knjigu broj K na vrh, jer onda prvo od ta
dva premještanja ne igra nikakvu ulogu - možemo ga zanemariti i tako dobiti kraći
protokol, pa ovaj prvi nije optimalan, što je u kontradikciji s pretpostavkom.

Dakle, ako je K broj knjige koju najprije stavljamo na vrh u optimalnom protokolu,
moramo nakon nje na vrh staviti sve knjige s manjim rednim brojem od K i nijednu
drugu knjigu. Sada je jasno da te knjige trebamo stavljati u poretku K, K-1, K-2,
..., 2, 1.

Nakon toga će prvih K brojeva biti (1, 2, ..., K), pa nas zanima da li je i nakon toga
niz sortiran, tj. da li slijede brojevi (K+1, K+2, ..., N). Da bi se to dogodilo, svi
brojevi veći od K moraju u početnom nizu činiti rastući podniz, jer se
premještanjem brojeva 1, 2, ..., K relativni poredak ostalih (većih) brojeva ne
mijenja, a na kraju on mora biti rastući.

Dakle, kao broj K možemo odabrati bilo koji broj takav da brojevi K+1, K+2, ..., N
čine rastući podniz u početnom nizu. Sada je jasno da ćemo, budući da tražimo
rješenje s najmanjim brojem premještanja, odabrati najmanji K za koji vrijedi
gornja tvrdnja.

Primijetimo da, ako broj K ima gornje svojstvo, onda to svojstvo ima i broj K+1, jer
ako brojevi K+1, K+2, ..., N čine rastući podniz, onda ga čine i brojevi K+2, K+3,
..., N. Zato traženi najmanji K možemo pronaći binarnim pretraživanjem, ili
promatrati brojeve N, N-1, N-2, ... i pronaći prvi od njih koji s prethodnima ne čini
padajući podniz.
Potrebno znanje:

Uočavanje pravilnosti, dokazivanje točnosti algoritma

Kategorija

Ad-hoc, binarno pretraživanje


HONI 2010/11 Zadatak LUNAPARK

2. kolo, 13. studeni 2010. Autor: Stjepan Glavina

Ako tablica ima neparan broj redaka, možemo se kretati desno do kraja prvog
retka, zatim skrenuti dolje, pa kretati se lijevo do početka drugog retka i onda opet
skrenuti dolje. Na taj način smo posjetili sva polja u prva dva retka pa možemo
zamisliti i da smo obrisali ta dva retka. Sada i dalje ima neparan broj redaka te
ponavljamo isti algoritam. Jednom kad ostane samo jedan redak, možemo lako
posjetiti sva polja do donjeg desnog kuta.

Dakle, ako je broj redaka neparan može se posjetiti sva polja pa je to optimalno
rješenje. Slična stvar se može napraviti i ako je broj stupaca neparan.

Najteži slučaj je onaj kad su i broj redaka i broj stupaca parni brojevi. Dokažimo da
je nemoguće posjetiti sva polja tablice.

Zamislimo da je tablica obojana crno-bijelo poput šahovske ploče. Gornji lijevi kut i
donji desni kut su bijele boje. Svaki put od gornjeg lijevog do donjeg desnog kuta
prvo uñe u polje crne boje, zatim u polje bijele boje, pa crne i tako dalje sve dok ne
završi u bijelom polju. Dakle, ulazi u jednak broj bijelih i crnih polja. Budući da put
kreće od gornjeg lijevog kuta, koji je bijele boje, na početku ima manje
neposjećenih bijelih od neposjećenih crnih polja. Iz toga proizlazi da je nemoguće
posjetiti sva polja.

Ukoliko izostavimo jedno crno polje, biti će moguće posjetiti sva ostala polja.
Ukoliko pak izostavimo neko bijelo polje, znači da ćemo sigurno morati izostaviti još
dva crna polja, što nikako nije optimalno.

Možemo proizvoljno odabrati crno polje koje nećemo posjetiti. Najbolje je odabrati
ono crno polje koje ima najmanju zabavnost. Preostaje još samo naći put koji će
posjetiti sva polja osim tog odabranog.

Rješenje:

Algoritam koji radimo možemo zamisliti na ovaj način: postavimo jednu figuricu u
gornji lijevi kut, a drugu u donji desni. Malo pomičemo jednu, malo drugu, a na
kraju se figurice sastaju u istom polju. Spojimo ta dva puta kojima su se figurice
kretale i to je rješenje.
Ako odabrano polje nije unutar prva dva retka, možemo se kretati prvom figuricom
desno do kraja prvog retka, zatim skrenuti dolje, pa kretati se lijevo do početka
drugog retka i onda opet skrenuti dolje. Sada obrišemo prva dva retka tablice i
nastavljamo algoritam.

Ukoliko pak odabrano polje nije unutar zadnja dva retka, možemo odrediti koji će
nam biti zadnji potezi u algoritmu. Zato se mičemo drugom figuricom: idemo prema
lijevo do početka zadnjeg retka, zatim gore, desno do kraja predzadnjeg retka i još
jednom gore. Sada brišemo zadnja dva retka.

Slično postupamo i onda kad odabrano polje nije u prva dva stupca ili kad nije u
zadnja dva stupca.

Ovim postupkom postepeno smanjujemo tablicu, koja će na kraju imati samo dva
retka i dva stupca. Rješenje u takvoj tablici je trivijalno: odaberemo bolji put od
desno-dolje i dolje-desno, te po tom putu mičemo prvu figuricu. Sada se one
konačno sastaju u istom polju.

Ovo se može implementirati tako da držimo dva niza sa smjerovima, jedan za prvu
figuricu, a drugi za drugu. Nakon što se one sastanu, ispišemo smjerove prve
figurice, a zatim u obrnutom poretku suprotne smjerove druge figurice.

Alternativno rješenje:

Ako tablica ima samo dva retka, može se jednostavnim algoritmom naći rješenje.
Ako se odabrano polje ne nalazi unutar prva dva retka tablice, možemo ih na već
opisan način eliminirati i time smanjiti tablicu.

Ako pak se odabrano polje nalazi unutar prva dva retka, mogu se posjetiti sva polja
unutar prva tri retka, osim odabranog. Zatim brišemo prva tri retka, nakon čega
ostaje tablica s neparnim brojem redova, za koju nam je već poznato kako dovršiti
rješenje.

Detalje ovog rješenja prepuštamo čitatelju.

Potrebno znanje:

Dokazivanje točnosti pohlepnog algoritma, uočavanje pravilnosti, redukcija


problema na manji problem

Kategorija
Ad-hoc, pohlepni algoritmi
HONI 2010/11 Zadatak CRNI

2. kolo, 13. studeni 2010. Autor: Stjepan Glavina

Na početku prebrojimo za svako polje koliko ima crnih pravokutnika kojima je to


polje u donjem desnom kutu.

Odaberimo neki redak R. Visinu stupca definiramo kao broj uzastopnih crnih polja u
tom stupcu, brojeći od retka R prema gore. Te visine stupaca čine histogram. Kroz
redak R se krećemo od polja u prvom stupcu pa sve do polja u posljednjem, te u
svakom trenutku održavamo rastuće crne stepenice sadržane od stupaca u
histogramu, od prvog stupca pa do trenutnog. Broj polja u tim stepenicama minus
jedan je broj crnih pravokutnika kojima je trenutno polje u donjem desnom kutu
(oduzimamo jedan jer pravokutnik koji se sastoji od samo jednog polja ne
smatramo crnim pravokutnikom).

Na isti način se može za svako polje prebrojati i broj crnih pravokutnika kojima je
to polje u donjem lijevom, gornjem desnom i gornjem lijevom kutu. Pomoću tih
izračunatih podataka još se može izračunati za svako polje koliko ima crnih
pravokutnika u podtablici od toga polja gore lijevo, dolje lijevo, gore desno i dolje
desno od njega.

Kad god odaberemo dva disjunktna crna pravokutnika, možemo povući izmeñu njih
horizontalan pravac, vertikalan pravac, ili pak oba.

Broj načina na koje možemo odabrati pravokutnike izmeñu kojih postoji vertikalan
pravac (A) se može izračunati tako da odaberemo stupac koji će biti desni rub
prvog pravokutnika. Onda je drugi pravokutnik negdje desno od njega. Broj
pravokutnika lijevo i desno od tog stupca se može očitati iz prethodno izračunatih
vrijednosti.

Analogno radimo i za nalaženje broja parova pravokutnika izmeñu kojih postoji


horizontalan pravac (B).

Broj parova pravokutnika izmeñu kojih postoji i horizontalan i vertikalan pravac (C)
se takoñer može izračunati. Odaberemo polje koje je u donjem desnom kutu prvog
pravokutnika, a drugi pravokutnik se onda nalazi negdje u podtablici dolje desno od
tog polja.

Konačno, rješenje je: A + B - C, zato što treći slučaj ukupno dva puta brojimo u
prva dva slučaja. Sve ovo se može izračunati u složenosti O( N2 ).
Potrebno znanje:

Dinamičko programiranje, održavanje histograma i njegove površine u linearnoj


složenosti

Kategorija

Dinamičko programiranje, prebrojavanje, uključivanje i isključivanje

You might also like