Professional Documents
Culture Documents
Opisi algoritama
Zadatak Planovi Autor: Nikola Pintarić
Pri upisu je B1 manji od B2 pa ako vrijedi da B1 nije tijekom obaveza onda je to i rješenje. U
suprotnom je rješenje B2.
Uočimo naprije da učenik koji je X-ti u redu očekuje da će dobiti točno X bombona. Kako
bismo odredili broj sretnih učenika, zapravo trebamo odrediti koliko postoji pozicija X u
zadanom nizu brojeva takvih da je X >= Bx . Jedan od načina na koji to možemo učiniti je da
svaki učitani broj uspoređujemo s njegovim rednim brojem (koji je to po redu učitani broj) te
povećavamo neki brojač ukoliko je učitani broj veći ili jednak njegovom rednom broju.
Vrijednost tog brojača nakon učitavanja svih N brojeva će biti traženo rješenje.
Za rješavanje zadatka sve što je bilo potrebno je prebrojati koliko se puta pojavljuju znakovi
‘A’, ‘K’, ‘Q’, i ‘J’ u svim kartama Ki zajedno.
R = 4 * A + 3 * K + 2 * Q + 1 * J
for j in s:
if j == 'A':
r += 4
elif j == 'K':
r += 3
elif j == 'Q':
r += 2
elif j == 'J':
r += 1
print (r)
Prvo ćemo u niz učitati sva odredišta koja su zadana, a u posebnu varijablu prvih nekoliko
početnih znakova odabranog odredišta. Za svako mjesto/odredište koje nam je zadano i koje
smo mogli birati provjerimo počinje li tim nizom znakova. Ako počinje, odredimo slovo koje
može biti birano u sljedećem odabiru tj. slovo koje slijedi nakon zadanog niza znakova. Tako
određeno slovo dodamo na prethodna odabrana slova.
L = []
for i in range(N):
L += [input()]
odrediste = input()
prva_sljedeća_slova = ''
d = len(odrediste)
for i in range(N):
if L[i][:d] == odrediste:
prva_sljedeća_slova += L[i][d]
tipkovnica = '***ABCDEFGHIJKLMNOPQRSTUVWXYZ***'
for i in tipkovnica:
if i not in prva_sljedeća_slova:
tipkovnica = tipkovnica.replace(i,'*')
print(tipkovnica[0:8],tipkovnica[8:16],tipkovnica[16:24],tipkovnic
a[24:32], sep = '\n')
Cijeli se zadatak svodi na ispravnu podjelu novčanica kako je opisano u prvom odlomku
teksta zadatka. Dakle, potrebno je raspodijeliti neke od N novčanica u dva dijela tako da je
svota novca u svakom od dijelova jednaka, a ukupna svota novca na neiskorištenim
novčanicama je najmanja moguća.
Naivnim algoritmom mogli smo isprobati sve moguće kombinacije i tako ostvariti 50%
bodova na zadatku. Budući da svaka novčanica može pripasti ili Kiletu ili Pogiju ili nijednom
od njih, zaključujemo da vremenska složenost takvog algoritma iznosi O(3n).
Iako se u zadatku to nije tražilo, savjetujemo da osmislite algoritam koji rješava ovaj zadatak
sa dodatnim ograničenjem memorije na 32 MB.
Znajući da brojevi na ulazu imaju najviše pet decimalnih mjesta, množeći ih sa 100 000
pretvaramo ih u prirodne brojeve. Mirkovi nepoznati brojevi (također pomnoženi sa 100 000)
očito su neki od djelitelja dobivenih brojeva.
Dakle, za svaki od dobivenih brojeva, redom od najmanjeg, treba pronaći neki njegov djelitelj
koji je “dobar”, tj. može pripadati traženom skupu Mirkovih početnih brojeva. Djelitelj je
“dobar” ako se svi njegovi višekratnici u zadanome intervalu nalaze među zadanim
brojevima, što je moguće efikasno provjeriti.
Dobivene riječi ćemo okrenuti, te ih ubaciti u prefiksno stablo. Dvije riječi se rimuju ako i
samo ako je čvor koji predstavlja jednu od njih roditelj čvora koji predstavlja drugu ili ta dva
čvora imaju zajedničkog roditelja.
Promatrajmo neki niz u kojem se svake dvije susjedne riječi rimuju. Niz počinje na nekom
čvoru u stablu te čini nekoliko koraka prema gore ili u stranu, tj. prema roditelju ili čvorovima
sa zajedničkim roditeljem. Jednom kad napravi korak prema dolje, tj. prema djetetu, može
raditi samo korake u stranu ili prema dolje.
Sada zadatak možemo riješiti dinamičkim programiranjem. Za svaki čvor izračunamo najveći
broj čvorova u njegovom podstablu koje možemo proći krećući se samo gore ili dolje
(svejedno je), te u stranu. Za svaki čvor možemo pretpostaviti da je on najviši čvor u nizu, te
za njega pronaći dva najduža puta među njegovom djecom. Također trebamo paziti da
brojimo sve čvorove sa zajedničkim roditeljem. Za detalje pogledajte službenu
implementaciju.
Veći je problem izračunati broj povoljnih odabira, tj. onih koji daju dvije jednake riječi. Ako se
neka riječ R pojavljuje na X mogućih mjesta, tada je jednom možemo pročitati na X načina, a
dvaput na X*X načina. Potrebno je, dakle, zbrojiti kvadrate svih ovih brojeva X, tj.
identificirati različite moguće riječi i znati na koliko se načina svaka od njih može pročitati.
To činimo koristeći hash funkciju koja string pretvara u broj radi lakše usporedbe. Hashiranje
je ovdje problematično zbog veličine broja K (duljine riječi). U slučaju gdje je M = N možemo
primijetiti da su sve riječi periodične s periodom N pa je dovoljno gledati duljinu K % N, a svi
se takvi hashevi mogu dovoljno brzo izračunati koristeći rolling hash pristup. To rješenje
nosilo je 100 bodova.
U općem slučaju možemo, kao pomoćni korak, izračunati sve hasheve čija je duljina
potencija broja 2, tako da hash duljine 2^(i+1) dobivamo kombinacijom dvaju hasheva duljine
2^i. Potom K zapišemo binarno, kao zbroj potencija broja 2, i time hash svake moguće riječi
dobivamo kao kombinaciju nekoliko izračunatih hasheva. Sortiranjem skupa hasheva
mogućih riječi možemo saznati koliko se puta svaki od njih pojavljuje i tako doći do tražene
vjerojatnosti.