160 likes | 304 Views
Nekaj zanimivih nalog z nedavnih regijskih tekmovanj. Iz Afrike ves čas prihaja kaj novega. Plinij 8:42. 2313 – Perfect Square (ACM South Africa 2006). Dano število n , ki je večkratnik 4 in 8 ≤ n < 2 32 , bi radi zapisali kot n = a 2 – b 2 , pri čemer naj bo a čim manjši.
E N D
Nekaj zanimivih nalog z nedavnih regijskih tekmovanj Iz Afrike ves čas prihaja kaj novega. Plinij 8:42
2313 – Perfect Square (ACM South Africa 2006) • Dano število n, ki je večkratnik 4 in 8 ≤ n < 232,bi radi zapisali kot n = a2 – b2, pri čemer naj bo a čim manjši. • Rešitev: • n = (a2 – b2) = (a – b)(a + b) = u·v,če pišemo u = a – b, v = a + b, a = (u + v)/2 • Torej pojdimo z u po vseh deliteljih n-ja, pri vsakem u določimo a in si zapomnimo najmanjši a. • Do vseh deliteljev pridemo tako, da n razcepimo na prafaktorje:delitelji = {1}; m := n;fori := 0, 1, 2, 3, … dobeginp := (i-to praštevilo); ifp·p > mthenbreak;whilemmodp = 0 dobegindelitelji := delitelji { d·p : d delitelji };m := m / p;end; (* while *)end; (* for *)ifm > 1 thendelitelji := delitelji { d·m : d delitelji }; • Seznam praštevil si pripravimo z Eratostenovim rešetom.Ker bo n < 232, potrebujemo praštevila do 216.
2316 – Peasant(ACM South Africa 2006) • Šahovnica n×n. (n ≤ 12) • Imamo le en tip figure, nekaj podobnega kmetu • Kmet na polju (x, y) napada nekatera polja oblike (x + c, y + r), pri čemer so pari (c, r) podani in za vsakega velja: 0 ≤ r ≤ 1, – n ≤ c ≤ n. • Torej kmet napada le (nekatera) polja v svoji in naslednji vrstici. • Naloga: postavi na šahovnico čim več kmetov, tako da ne bo noben nobenega napadal. • Opazimo: na dogajanje v vrstici y vplivajo le kmetje v tej in v prejšnji vrstici (y – 1); tisti v vrsticah 1, …, y – 2 pa ne. • Rešitev sestavljajmo vrstico za vrstico. • V opis podproblema vključimo ne le to, koliko vrstic je že sestavljenih, ampak tudi to, katera polja v naslednji vrstici so napadena. • To si lahko privoščimo, ker je n majhen. • Možnih podproblemov je torej O(n· 2n)
2316 – Peasant(ACM South Africa 2006) • Dinamično programiranje: • Naj bo f(y, A) največje število kmetov, ki se jih da postaviti na prvih y vrstic šahovnice, če hočemo, da so zaradi njih v vrstici y + 1 napadena natanko polja A. • To je za 0 ≤ y ≤ n in za A {1, …, n}. • V praksi predstavimo A kot n-bitno celo število (od 0 do 2n – 1). • Robni primer: f(0, A) = 0 za vsak A. • Kasneje lahko računamo takole (za y = 1, 2, …, n):forA := 0 to 2n – 1 dof[y, A] := –;forA := 0 to 2n – 1 dobegin (* Recimo, da so v vrstici y že napadena polja iz A. *)forB := 0 to 2n – 1 dobegin (* Ali bi lahko v vrstico y postavili kmete na polja iz B? *)if (bi kmetje v tej vrstici napadali drug drugega) thencontinue; (* ‡ *)ifA B {} thencontinue; (* nekateri bi bili napadeni iz prejšnje vrstice *)C := (polja, ki bi jih kmetje iz B napadli v naslednji vrstici); (* ‡ *) f[y, C] := max(f[y, C], f[y – 1, A] + |B|); (* ‡ za |B| *) end; (* for B *)end; (* for A *) • Na koncu seštejemo f(n, A) po vseh možnih A. • ‡ označuje stvari, ki jih lahko potabeliramo. • Časovna zahtevnost: O(n 2n 2n) = O(n 4n).
2396 – Delay(ACM South Africa 2006) • Naloga sprašuje po najdaljši poti v danem grafu. • “The network consists of n devices (computers or switches), connected by n– 1 cables. There is exactly one route from any device to any other device.” • Povezan, neusmerjen graf, n točk in n – 1 povezav… • Ne gre drugače, kot da je acikličen – torej je ta graf drevo. • Izberimo poljubno točko za koren, od tam ga preiščimo v globino in tako vzpostavimo odnose oče-sin po celem drevesu. • Preprost rekurzivni razmislek: • Najdaljša pot po drevesu bodisi gre skozi koren bodisi ne gre. • Če ne gre skozi koren, leži v celoti znotraj enega od poddreves. • Torej so kandidatke kar najdaljše poti za vsako od posameznih poddreves. • Če gre skozi koren, se mora vanj povzpeti iz enega od poddreves in se nato iz njega spustiti v kakšno drugo poddrevo. • Torej je smiselno izbrati najgloblji dve poddrevesi.
2396 – Delay(ACM South Africa 2006) • Zapišimo našo rešitev še s podprogramom:function Reši(u: integer): vrne par (globina, dolžina najdaljše poti);beginif (u je list) thenreturn (1, 0);najPot := 0; najGlob := 0; najGlob2 := 0;for (za vsakega u-jevega otroka, v) dobegin (g, n) := Reši(v);ifg ≥ najGlobthenbeginnajGlob2 := najGlob; najGlob := gend;elseifg > najGlob2thennajGlob2 := najGlob;ifn > najPotthennajPot := v;end; (* for *)return (najGlob + 1, max{najPot, najGlob + najGlob2});end; (* Reši *) • To lahko počnemo pravzaprav v isti sapi, ko s preiskovanjem v globino sploh odkrivamo strukturo drevesa.
3245 – Partial Overlapping(ACM Arab and North African Regional Contest 2004) • Karirasta mreža črk, velika w×h. (w, h ≤ 1000) • Če jo malo zamaknemo, se mogoče lepo prekriva sama s sabo: abcdef abcdef ghabcd ghabcdef ijghab ijghabcd klijgh klijghab klijgh • Radi bi našli prekrivanje z največjo površino. • V bistvu moramo torej za vsak zamik (dx, dy) preveriti, ali se zgornja leva podmatrika velikosti (w – dx, h – dy) ujema s spodnjo desno podmatriko te velikosti. • Naivni postopek bi za to porabil O(w·h) časa. Za vse možne zamike torej skupno O(w2h2). • Malo boljša rešitev: vse konce vseh vrstic zložimo v suffix tree;potem lahko v času O(w·h) preverimo ujemanje za vse možne dx pri fiksnem dy. Vsega skupaj nam bo ta rešitev vzela O(h2w) časa.
3245 – Partial Overlapping(ACM Arab and North African Regional Contest 2004) • Spomnimo se Rabin-Karpovih hash kod za nize:h(s1s2 … sk) = (pk–1s1 + pk–2s2 + … + p2sk–2 + psk–1 + sk) mod m. • p in m sta neki vnaprej izbrani konstanti. • Kot vedno pri hash kodah: če je s t, je z veliko verjetnostjo tudi h(s) h(t). • Lepota RK-hash kod: če s podaljšamo z leve ali desne za eno črko, je izračun nove hash kode zelo poceni:h(s1s2 … sk) = (ph(s1 … sk–1) + sk) mod m.h(s1s2 … sk) = (pk–1s1 + h(s2 … sk)) mod m. • Mi pa jih zdaj posplošimo na 2-d tabele črk. Naj bodo r1, r2, …, rl nizi dolžine k, ki predstavljajo vrstice naše tabele. Definirajmo:H(r1, …, rl) = (ql–1h(r1) + ql–2h(r2) + … + q2h(rl–2 ) + qh(rl–1 ) + h(rl)) mod m • m naj bo enak kot zgoraj, q pa je še neka nova konstanta. • Hitro se vidi, da če matriki (r1; r2; …, ; rl) dodamo zgoraj ali spodaj novo vrstico, ali pa na levi ali desni nov stolpec, je mogoče novi H izračunati v času O(1) iz starega, če poznamo h novega stolpca ali vrstice. • h-je za vse začetke in konce vseh stolpcev in vrstic lahko izračunamo v času O(wh) in jih hranimo v neki tabeli. • Potem lahko tudi H-je za vse zgornje leve podmatrike in vse spodnje desne podmatrike izračunamo v času O(wh) in jih hranimo v neki tabeli. • S primerjavo H-jev za enako velike zgornje leve in spodnje desne podmatrike dobimo kandidate za primerna prekrivanja. • Pri njih potem primerjamo črke neposredno; začnimo pri tistih kandidatih, ki obetajo največje prekrivanje.
3762 – A-to-Z(ACM Arab and North African Regional Contest 2006) • Imamo slovar 50000 besed, vsaka dolga ≤ 64 znakov. • Radi bi sestavili zaporedje besed iz slovarja. • Prva beseda se mora začeti na črko x. • Zadnja se mora končati na črko y. • Konec neke besede in začetek naslednje se morata prekrivati za vsaj dve črki. • Skupna dolžina besed mora biti čim manjša, pri čemer pa prekrivajoči se deli štejejo le enkrat. • Primer: x = ‘a’, y = ‘s’, “about (out)side (ide)as” ima ceno 11. • Nalogo lahko elegantno prevedemo na problem najkrajših poti v grafu. • Mislimo si po eno točko za vsako besedo. • Če se u in v prekrivata za k črk (k ≥ 2), si mislimo povezavo (uv) z dolžino |v| – k. • Dodajmo še dve posebni točki s in t. • Če se u začne na črko x, dodajmo povezavo (su) dolžine |u|. • Če se u konča na črko y, dodajmo povezavo (ut) dolžine 0. • Vidimo, da vsaka pot po grafu predstavlja neko veljavno zaporedje besed, skupna dolžina poti pa je ravno cena zaporedja. • Iščemo najkrajšo pot od s do t (npr. z Dijkstrovimalgoritmom). • Vprašanje je še, kako učinkovito priti do grafa.
3762 – A-to-Z(ACM Arab and North African Regional Contest 2006) • Kako najti vse prekrivajoče se pare besed? • Konec u-ja se mora ujemati z začetkom v-ja. • Ne bi radi preizkusili vseh O(500002) parov (u, v). • Rešitev: • Lahko sestavimo drevo, v katerem bodo na črkah povezave. Za vsako končnico vsake besede v iz slovarja dodajmo to končnico v drevo. suffix tree • Za besedo dolžine d nam bo to vzelo O(d2) časa. Ker imamo d ≤ 64, je to najbrž OK. Obstajajo tudi hitrejši postopki. • Lahko pa končnice besed pomečemo v hash tabelo. • Pomagajmo si z Rabin-Karpovimi hash kodami. • To bo le O(d) za vsako besedo. • Nato za vsak u plezajmo dol po drevesu od korena naprej (sledimo povezavam, ki ustrezajo črkam u-ja). • Tako za vsak začetek u-ja vidimo, ali je enak koncu kakšnega v-ja. • S tem bomo zlahka našteli vse naslednike u-ja, ko jih bomo pri Dijkstri potrebovali. Grafa sploh ni treba predstaviti eksplicitno!
3248 – Chop Ahoy!(ACM Arab and North African Regional Contest 2004) • Iz števila n lahko naredimo kakšno drugo število takole: • n zapišemo v desetiškem zapisu • razsekamo ga na dva ali več kosov • vsak kos kvadriramo in kvadrate seštejemo. • Primer: 506 50|6 2536. • Vprašanje je, kako s čim manj takimi koraki iz začetnega števila s dobiti končno število t. • Pri tem ne smemo nikoli uporabiti števil, večjih od 107. • To je problem najkrajše poti v grafu: • Vsakemu številu pripada ena točka. • Povezava (u v), če se da iz u v enem koraku dobiti v. • Vse povezave so enako dolge, zato lahko uporabimo iskanje v širino. • Grafa ni treba predstaviti eksplicitno. Za vsako točko bo treba največ enkrat našteti njene naslednice.
3248 – Chop Ahoy!(ACM Arab and North African Regional Contest 2004) • Za naštevanje naslednic uporabimo dinamično programiranje: naj bodo u1…uk števke u-ja v desetiškem zapisu;Ak+1 := {0};fori := kdownto 1 dobeginAi := {};forj := itokdoAi := Ai {(uiui+1…uj–1uj)2 + v : v Aj+1};end; (* for i *)Na koncu imamo v A1 vse naslednice u-ja. • Pri k-mestnem številu u imamo k – 1 položajev, kjer lahko prerežemo. Torej ima u največ 2k – 1 naslednic. • Pri nas gre k do 7, ker smemo uporabljati le števila do 10 milijonov.
Bursary(South African Computer Olympiad 2004) • Imamo n ≤ 2000 ponudb za štipendije • i-ta ponudba nam obljublja vi enot denarja, vendar z omejitvijo, da smemo iz vseh štipendij pridobiti le mi, s fušanjem pa še nadaljnjih ti enot • 1 ≤ vi ≤ mi ≤ 100000 in 1 ≤ ti ≤ 100000 • Torej, če je S {1, …, n} množica izbranih štipendij: • V := SiSvi , M := min{mi : iS}, T := min{ti : iS} • bomo zares dobili min(V, M) + T enot denarja. • To bi radi maksimizirali. • Opazimo: • M in T gresta sicer lahko do 100000 (V mogoče celo do 200 mio) • Toda M je vedno enak nekemu mi , T pa vedno nekemu ti • Torej je zanju le n ≤ 2000 možnih vrednosti! • Lahko pregledamo vse možne pare (M, T) in z njimi kaj naredimo.
Bursary(South African Computer Olympiad 2004) • Recimo, da nas zanimajo izbori z nekim konkretnim T • Torej se omejimo na ponudbe {i : ti ≥ T} • Zdaj ko je T fiksiran, nam ostane le še to, da maksimiziramo min(V, M) • Če smo vzeli neko ponudbo i, ki ima nek mi , potem ni nobene škode v tem, če vzamemo tudi vse ponudbe j, ki imajo mj ≥ mi :zaradi njih se ne bo M nič spremenil, V pa se bo celo povečal • Torej uredimo ponudbe po padajočem mi in jih jemljimo od začetka • V se povečuje, M se zmanjšuje, po vsakem koraku vzemimo min(V, M) + T in si ga zapomnimo, če je to najboljša rešitev doslej. • To je O(n log n) zaradi urejanja – pri tem konkretnem T • Ker imamo O(n) možnih vrednosti T, bo vse skupaj O(n2 log n) • No, v resnici, ko T zmanjšamo, se množica {i : ti ≥ T} le malo poveča – seznama po naraščajočem mi ni treba urejati znova, pač pa le vrinemo nove elemente vanj. • Tako bo vse skupaj O(n2).
2552 – Palindromes(ACM Arab and North African Regional Contest 2002) • Število je palindrom, če se (v desetiškem zapisu) enako prebere z leve in z desne (323, 947749, …) • Če je negativno, minus ignoriramo • Koliko števil med vključno L in U je palindromov? (– 106 ≤ L ≤ U ≤ 106) • Preprosta rešitev:vara : array [– 106 – 1 .. 106] of integer;a[–106 – 1] := 0;forn := –106+1 to 106doa[n] := a[n – 1] + (JePalindrom(n) ? 1 : 0); • Torej: a[n] je število palindromov od –106 do n. • Potem pri danih L in U le izračunamo a[U] – a[L – 1]. • Kaj pa, če bi šla L in U do 109 ali še dlje? • Tabela a je prevelika za pomnilnik. • Tudi zanka po vseh n bi trajala predolgo.
2552 – Palindromes(ACM Arab and North African Regional Contest 2002) • Za začetek se znebimo komplikacij z negativnimi števili • Naj bo f(n) število palindromov iz množice {0, 1, …, n – 1}. • Nalogo rešimo takole:functionKoliko(L, U: integer): integer;beginifU < 0 thenreturn Koliko(–U, –L)elseifL < 0 thenreturn Koliko(0, U) + Koliko(1, L)elsereturnf(U + 1) – f(L);end; (* Koliko *) • Ostane le še izračun f(n). • Recimo, da je n = (a1a2 … ak)10 • Kateri palindromi so manjši od n? • Vsi enomestni, dvomestni, …, (k – 1)-mestni palindromi • Pri tem je m-mestnih palindromov 9 · 10 m/2 – 1,razen enomestnih, kjer je še 0 in jih je zato 10, ne 9 • Potem pa še: vsi k-mestni, ki se začnejo na a1a2 … at – 1b in je b eden od 0, 1, 2, …, at– 1. • Pri t ≤ k/2 je takih palindromov at· 10k/2 –t • Pri t = 1 ne dovolimo b = 0, ker potem število ne bi bilo k-mestno. Zato v formuli dobimo at – 1, ne at. • Pri t > k/2 nam števke a1a2 … at – 1 predpisujejo že vsaj polovico števila ali pa še več.Lahko se torej zgodi, da takega palindroma sploh ni (npr. 1234xx) ali pa je en sam (npr. 1233xx).