54. ročník Matematické olympiády 2004/2005
|
|
- Dagmar Vlčková
- před 6 lety
- Počet zobrazení:
Transkript
1 54. ročník Matematické olympiády 2004/2005 Komentáře k úlohám domácího kola kategorie P P-I-1 Prádelna Nejprve se zaměřme na to, kolika pračkami bude potřeba vybavit prádelnu. Je zřejmé, že je potřeba alespoň tolik praček, kolik má Bořivoj nejvýše v jednom okamžiku zákazníků. Později ukážeme, že tento počet praček je i dostatečný. Nejprve si však rozmysleme, jak určit maximální počet zákazníků prádelny v jednom okamžiku. Budeme simulovat dění v prádelně podle času a zároveň počítat počet zákazníků v prádelně. Událostí nazveme příchod nebo odchod některého ze zákazníků. Pro každého zákazníka si vytvoříme dvojici událostí: jednu pro příchod a druhou pro odchod zákazníka. Vytvořené události setřídíme podle jejich času a budeme sledovat příchody a odchody v pořadí, v němž jsou setříděny. Události se stejným časem zpracujeme naráz. Při odchodu snížíme počet zákazníků v prádelně, naopak při příchodu ho zvýšíme. Hledaný maximální počet zákazníků v jednom okamžiku je pak zřejmě maximum z takto získaných počtů zákazníků v prádelně. Nyní ukážeme, že tento počet praček je dostatečný tím, že nalezneme přiřazení praček zákazníkům prádelny. Znovu spustíme simulaci příchodů a odchodů zákazníků. U každé pračky si budeme pamatovat, jestli je obsazená. V jednom okamžiku nejprve uvolníme pračky, které byly používány zákazníky, co právě odešli, a pak přiřadíme volné pračky nově příchozím zákazníkům. Zřejmě každému zákazníkovi takto přiřadíme jednu pračku a tedy počet praček je dostatečný. Při samotné implementaci popsaného řešení ještě můžeme použít několik triků, jak náš algoritmus malinko vylepšit. Abychom se vyhnuli složitému zpracování událostí se stejným časem naráz, setřídíme události tak, že události odchodu jsou zařazeny před příchody, které nastanou ve stejný čas. Pak můžeme nejprve zpracovat odchody a poté příchody tím zůstane korektnost algoritmu při obou simulacích zachována. Další drobné vylepšení spočívá ve sloučení obou simulací do jedné. Začneme s prádelnou, ve které nejsou žádné pračky. Při příchodu zákazníka ho zkusíme umístit k nepoužívané pračce. Pokud žádná taková pračka neexistuje, vytvoříme v prádelně novou pračku, ke které zákazníka pošleme. Při odchodu zákazníka jeho pračku uvolníme. Hledaný minimální počet praček je počet praček, které jsme v prádelně museli vytvořit (počet praček, které existují, je roven maximálnímu počtu zákazníků, kteří byli dosud v prádelně ve stejném okamžiku). Zbývá odhadnout časovou a paměťovou složitost našeho algoritmu. Nejprve musíme události setřídit, na což spotřebujeme čas O(N log N) při použití vhodného třídícího algoritmu. Připomeňme, že N je počet zákazníků prádelny. V implementaci jsme použili algoritmus quicksort, který má složitost O(N log N) sice jen v průměrném případě, ale místo něj lze samozřejmě použít libovolný třídící algoritmus s časovou složitostí O(N log N) v nejhorším případě. Poté provedeme jeden průchod setříděnými událostmi. Na zpracování jedné události nám stačí konstantní časová složitost. Celá simulace dění v prádelně má tak časovou složitost O(N). Celková časová složitost našeho algoritmu je tedy O(N log N). Paměťová složitost je O(N), což je množství paměti potřebné na uložení zakázek, volných a používaných praček (těch je nejvíce tolik, kolik je zákazníků) a setříděných příchodů a odchodů do paměti. #include <stdio.h> #include <stdlib.h> #define MAX_N 100 struct zakazka { long z,t; }; struct udalost { long t; char prichod; int zakaznik; }; // začátek a doba trvání // čas události // příchod nebo odchod // číslo zákazníka této události // porovnání udalostí: třídí se podle času a v případě shody časů nejdříve odchod int udalost_cmp(const void *e1,const void *e2) { if (((struct udalost *)e1)->t == ((struct udalost *)e2)->t) return ((struct udalost *)e1)->prichod - ((struct udalost *)e2)->prichod; return ((struct udalost *)e1)->t - ((struct udalost *)e2)->t; } int N; struct zakazka zakazky[max_n]; int stack[max_n]; int stack_top=0; // index prvního neobsazeného místa v stacku int prirazeni_pracek[max_n]; int pocet_pracek=0; 1
2 struct udalost udalosti[2*max_n]; FILE *fr,*fw; int main(void) { int i; fr=fopen("pradelna.in","r"); // načtení dat fscanf(fr,"%d",&n); for (i=0;i<n;i++) fscanf(fr,"%ld %ld",&zakazky[i].z,&zakazky[i].t); fclose(fr); for (i=0;i<n;i++) { // vytvoření událostí udalosti[2*i].t=zakazky[i].z; // příchod udalosti[2*i].prichod=1; udalosti[2*i].zakaznik=i; udalosti[2*i+1].t=zakazky[i].z+zakazky[i].t; // odchod udalosti[2*i+1].prichod=0; udalosti[2*i+1].zakaznik=i; } qsort(udalosti,2*n,sizeof(struct udalost),udalost_cmp); for (i=0;i<2*n;i++) // simulace provozu if (udalosti[i].prichod) { int pracka; if (!stack_top) /* nová pračka */ pracka=++pocet_pracek; else pracka=stack[--stack_top]; prirazeni_pracek[udalosti[i].zakaznik]=pracka; } else { stack[stack_top++]=prirazeni_pracek[udalosti[i].zakaznik]; } fw=fopen("pradelna.out","w"); // vypsání výstupu fprintf(fw,"%d\n",pocet_pracek); for (i=0;i<n;i++) fprintf(fw,"%d\n",prirazeni_pracek[i]); fclose(fw); } return 0; P-I-2 Závody Tuto úlohu budeme řešit přímočaře. Budeme postupně číst čísla švábů, vždy zjistíme, kolik již doběhlo švábů s číslem vyšším, než je číslo právě zpracovávaného švába, a tento počet přičteme k výslednému počtu opačně uspořádaných dvojic. Takto zjevně započítáme každou opačně uspořádanou dvojici švábů právě jednou a získáme tedy hledanou míru promíchanosti. Pokud bychom se spokojili s kvadratickou časovou složitostí, mohli bychom počet švábů s vyšší číslem zjištovat přímým průchodem již načtených čísel. My bychom ale rádi dosáhli lepší časové složitosti, a proto musíme být chytřejší. Nadále budeme předpokládat, že N (počet švábů) je mocnina dvojky pokud není, můžeme si snadno představit, že vstupní posloupnost je doplněna tak, aby její délka byla mocninou dvou a nic tím nezkazíme (vstup si prodloužíme nejvýše dvakrát a počet dvojic ve špatném pořadí se nezmění). Budeme si průběžně udržovat informaci, kolik dosud načtených čísel bylo v intervalu [N/2,..., N 1], kolik v intervalech [N/4,..., N/2 1] a [N/2,..., 3N/4 1] a tak dále. Na počátku jsou tyto počty zjevně nulové. Když přečteme další číslo, podíváme se, zda je menší než N/2. Pokud ano, přičteme k výsledku počet čísel z intervalu [N/2,..., N 1] a pokračujeme v testování na intervalu [0,..., N/2 1]. Jinak zvýšíme počet čísel v intervalu [N/2,..., N 1] a pokračujeme v testování na intervalu [N/2,..., N 1]. Obecně na každém intervalu se podíváme, zda je nové číslo menší než střed intervalu. Pokud je, přičteme k výsledku počet čísel z horní poloviny intervalu a pokračujeme v dolní polovině. Pokud není, zvýšíme počet čísel v horní polovině intervalu o jedna a pokračujeme na ní v testování. Takto postupujeme, dokud interval nemá délku jedna. Tímto způsobem jsme dokázali zjistit počet již načtených čísel větších než aktuální číslo a zároveň jsme do naší struktury aktuální číslo zahrnuli. Protože se v každém kroku délka intervalu zkrátí na polovinu, jedno zjištění počtu větších čísel bude trvat O(log N). Celková časová složitost tedy je O(N log N). Paměťová složitost našeho algoritmu je O(N). Ve vzorovém programu se používá dvou ne zcela obvyklých obratů, a proto je zde alespoň stručně vysvětlíme. Zjišťování, do které poloviny intervalu aktuální číslo spadá, provádíme tak, že se podíváme na příslušný bit čísla (označme b = log 2 N; nejdříve testujeme b 1-tý bit, pak b 2-tý až nakonec nultý bit) a pokud je 0, číslo je v dolní polovině intervalu, pokud 1, číslo je v horní polovině. Počet čísel v jednotlivých intervalech máme uložen v poli Vetsi. Na první pozici je uložen počet čísel 2
3 v jediném intervalu délky N/2 (to je interval [N/2,..., N]), na dalších dvou pozicích počet čísel ve dvou intervalech délky N/4 (to jsou intervaly [N/4,..., N/2 1] a [3N/4,..., N]), na dalších čtyřech pozicích počet čísel ve čtyřech intervalech délky N/8 atd. Intervaly stejné délky jsou vždy uspořádány vzestupně podle svých počátků. Rozmyslete si, že pokud je počet čísel v horní polovině nějakého intervalu uložen na pozici i, tak počet čísel ve druhé čtvrtině tohoto intervalu je uložen na pozici 2 i a počet čísel ve čtvrté čtvrtině je uložen na pozici 2 i + 1. program Zavody; const MAXN = 8192; IFILE = zavody.in ; OFILE = zavody.out ; var Vetsi : Array[1..MAXN] of Integer; {Pole s počty větších prvků} N, C : Integer; {Počet čísel; Aktuálně načtené číslo} bits : Integer; {Nejbližší vyšší mocnina dvou od N} Inverzi : Longint; {Počet opačně uspořádaných dvojic} i : Integer; {Pomocná promenná} inp, out : Text; {Vstupní a výstupní soubor} {Spočte dosavadní počet čísel vetších než C a C zařadí} function Zarad(C : Integer) : Integer; var i : Integer; {Pomocná proměnná} pocet : Integer; {Počet vetších čísel než C} act : Integer; {Aktuální vrchol ve stromu} pocet := 0; act := 1; for i := bits-1 downto 0 do if (C and (1 shl i)) = 0 then {Spadá číslo do spodní poloviny?} pocet := pocet + Vetsi[act]; {Započteme čísla z horní poloviny} act := 2*act; end else {Číslo spadá do horní poloviny} Inc(Vetsi[act]); {Zvýšíme počet čísel v horní polovině} act := 2*act+1; Zarad := pocet; Inverzi := 0; Assign(inp, IFILE); Reset(inp); ReadLn(inp, N); bits := 0; while (1 shl bits < N) do Inc(bits); for i := 1 to (1 shl bits) do Vetsi[i] := 0; for i := 1 to N do Read(inp, C); Inverzi := Inverzi + Zarad(C); Close(inp); Assign(out, OFILE); Rewrite(out); WriteLn(out, Inverzi); Close(out); end. {Zjistíme nejbližší vyšší mocninu dvou} {Inicializace} {Výpočet začíná} 3
4 P-I-3 Fylogenetika Nejprve si zadefinujme některé pojmy a značení. Pojmy slovo a řetězec budou v následujícím textu znamenat to samé konečnou posloupnost znaků z nějaké konečné abecedy (v našem případě A, C, G a T ). Například AAA a GGAGCTG jsou řetězce. Speciální případ řetězce je prázdný řetězec, tj. takový, který neobsahuje žádné znaky. Budeme ho značit λ. Délka řetězce je počet znaků, z nichž se skládá. Délku řetězce v si budeme značit v. Tedy například AAA = 3, λ = 0. Jsou-li u a v řetězce, označíme uv jejich spojení. Tedy pokud třeba u = AGG a v = CCT, je uv = AGGCCT. Počátečnímu úseku řetězce budeme říkat jeho prefix tedy slovo u je prefixem slova v, pokud existuje řetězec w takový, že uw = v. Koncový úsek řetězce označíme jako jeho suffix. Slovo samotné je svým prefixem i suffixem (položíme-li w rovno prázdnému řetězci). Prefix (resp. suffix) slova v je netriviální, pokud je různý od v. Podřetězec řetězce v je libovolný souvislý úsek znaků obsažený ve v tedy w je podřetězec v, jestliže existují (ne nutně neprázdná) slova z a k taková, že v = zwk; jinak řečeno, pokud je w suffixem nějakého prefixu slova v. Nyní se můžeme pustit do řešení úlohy. Zadané řetězce si označme s 1, s 2,..., s n. S bude součet jejich délek, tedy S = s 1 + s s n. Ze slov s i si sestavíme vyhledávací automat. Vyhledávací automat je struktura, umožňující pro libovolný řetězec t určit všechna slova s i, která se vyskytující jako podřetězec v t, v lineárním čase. Když toto budeme umět, řešení úlohy je již jednoduché tento postup provedeme postupně pro t = s 1, t = s 2,..., t = s n, čímž si zjistíme postupně předky prvního, druhého,..., n-tého organismu. Časová složitost bude O(S + čas na konstrukci automatu + délka výstupu). Nyní zbývá vytvořit takový automat. Vyhledávací automat se skládá ze dvou částí trie postavené z řetězců s i a takzvané zpětné funkce. Popis trie začneme příkladem takto vypadá trie pro řetězce ze vzorového vstupu v zadání: Trie je strom, jehož vrcholy odpovídají všem prefixům řetězců s i. Když má několik řetězců s i stejný začátek, odpovídá tomuto společnému prefixu jen jeden vrchol. Synové vrcholu odpovídajícího řetězci w jsou vrcholy odpovídající řetězcům wx, kde x je nějaký znak abecedy, v našem případě A, C, G nebo T. Každý vrchol má tedy nejvýše čtyři syny, ale může mít i méně, pokud žádné z s i nezačíná na wx. Kořen stromu odpovídá prázdnému řetězci. Některé vrcholy trie odpovídají slovům z s i například vrcholy, které nemají žádné syny, ale mohou to být i vrcholy uvnitř trie, pokud je některé ze slov prefixem jiného. Ostatní vrcholy budeme označovat jako pomocné. O slovu budeme říkat, že je reprezentováno v trii, pokud je to jedno ze slov s i, pro které jsme trii postavili. O slovu budeme říkat, že je v trii obsaženo, pokud mu odpovídá nějaký vrchol trie (může být i pomocný). Každé slovo, které je v trii reprezentováno, je v ní samozřejmě i obsaženo, opačné tvrzení obecně neplatí. Ve zbytku textu budeme občas ztotožnovat vrcholy trie se slovy, která jim odpovídají. Budeme-li například mít funkci, která vrcholu trie odpovídajícímu slovu v přiřazuje jiný její vrchol odpovídající slovu w, budeme občas pro zjednodušení říkat, že tato funkce přiřazuje slovu v slovo w. V každém vrcholu trie budeme mít ukazatele na jeho čtyři syny odpovídající jednotlivým písmenům. Někteří z jeho synů samozřejmě nemusí existovat, v tom případě bude příslušný ukazatel nil. Kromě toho bude vrchol obsahovat hodnotu typu boolean udávající, zda daný vrchol odpovídá nějakému slovu reprezentovanému v trii, nebo zda je pouze pomocný. Zjistit, zda je v trii obsaženo nějaké slovo, lze snadno v čase lineárním v délce tohoto slova: Začneme v kořeni. Z něj se posuneme do syna odpovídajícího prvnímu písmenu slova, z tohoto syna dále po hraně odpovídající druhému písmenu, atd. Pokud narazíme na nil dříve, než dojdeme ke konci slova, toto slovo se v trii nevyskytuje. Až dojdeme do vrcholu, který odpovídá zadanému slovu, ještě zkontrolujeme, zda je toto slovo v trii reprezentováno, tj. zda příznak vrcholu, do kterého jsme přišli, je true. Obdobně můžeme trii postavit provádíme postup analogický hledání, jen ve chvíli, kdy vypadneme z trie (tj. narazíme na nil), začneme stavět novou cestu. Tento postup nám dohromady zabere čas O(S). Dále si nadefinujeme zpětnou funkci f, která každému vrcholu trie přiřadí nějaký jiný, odpovídající kratšímu slovu (proto zpětná). Pro vrchol w bude f(w) definováno jako vrchol v takový, že v je nejdelší netriviální suffix w obsažený v trii. 4
5 Jednoduchý způsob, jak zpětnou funkci spočítat, je tedy tento: Vezmeme si slovo w a zahodíme z něj první písmeno. Pokud je takto vzniklé slovo v obsaženo v trii, je f(w) = v. Jinak z něj znovu zahodíme první písmeno a postup opakujeme, dokud hodnotu zpětné funkce neurčíme to se určitě stane, neboť se zcela jistě zastavíme nejpozději na prázdném řetězci. Pro vzorový vstup f(ata) = f(ca) = f(catatga) = A, f(atat) = f(cat) = AT, f(cata) = ATA, f(catat) = ATAT, f(a) = f(c) = f(at) = f(catatg) = f(catatgg) = λ. Význam funkce f je tento: Nechť máme nějaký text a chceme zjistit, která slova obsažená v trii končí na zadané pozici v tomto textu. Nechť nám navíc někdo prozradí, že s je nejdelší takové slovo. Pak f(s) je druhé nejdelší, f(f(s)) třetí nejdelší, atd., dokážeme je tedy v lineárním čase vypsat (a navíc seřazené podle délky). To se nám bude hodit, protože při hledání pomocí automatu si budeme pamatovat pro každou pozici v textu vždy právě toto slovo s (přesněji řečeno vrchol v trii, který mu odpovídá). Výše popsaný triviální postup, jak f spočítat, by nám zabral čas O(S 3 ) pro každý z nejvýše S vrcholů bychom museli provést hledání řádově S řetězců, jejichž délka může být až S. Samozřejmě bychom to chtěli zvládnout rychleji. K tomu použijeme postup založený na dynamickém programování. Funkci f budeme postupně počítat od nejkratších slov k delším. Pro jednopísmenná slova je f(x) = λ. Uvažujme nyní slovo wx, kde x je jeho poslední písmeno. Označme v = f(wx). Víme, že v musí být nějaký suffix wx, tedy v končí na x (pokud není prázdné), tedy v = v x pro nějaké slovo v, které je suffixem w. Nyní využijeme toho, co jsme si ukázali v předchozím odstavci všechny suffixy w, které jsou obsaženy v trii, jsou f(w), f(f(w)), atd. Nás zřejmě zajímá nejdelší z nich, který se dá rozšířit o písmeno x tak, aby výsledné slovo bylo obsaženo v trii. Algoritmus na určení f(wx) bude tedy tento: Označme w = f(w), tuto hodnotu již máme spočítanou. Pokud w x je obsaženo v trii, je f(wx) = w x, neboť w je nejdelší suffix w v trii a tedy f(wx) nemůže být delší. Pokud w x v trii není, vyzkoušíme w = f(w ) a takto pokračujeme, dokud buď nenalezneme hodnotu pro f(wx), nebo nedorazíme k prázdnému řetězci pak f(wx) = λ. Testování, zda w x je v trii, zvládneme v konstantním čase, neboť známe vrchol v trii odpovídající řetězci w. Jaká je časová složitost tohoto postupu? Při stanovování f pro jeden vrchol se nám může stát, že se funkcí f budeme muset vracet až S-krát, na první pohled by se tedy mohlo zdát, že časová složitost bude O(S 2 ). Můžeme ovšem nahlédnout, že toto se nám nemůže stát příliš často: f(wx) bude jen o jedna delší, než slovo w, k němuž jsme dospěli při vracení se, tedy oproti f(w) může být nanejvýš o jedna delší. Na to, abychom se mohli vracet o k hladin tedy nejprve musíme udělat alespoň k kroků, v nichž se nevracíme vůbec a tedy je zvládneme v konstantním čase. Tato úvaha není zcela přesná, nicméně není obtížné ji domyslet do všech detailů. Dohromady se tedy budeme vracet nejvýše S a časová složitost bude O(S). Vraťme se ještě k motivaci pro definici funkce f. Řekli jsme si, že f(s), f(f(s)), atd. jsou všechny suffixy slova s obsažené v trii. Nijak jsme však nerozlišovali, zda se jedná o původně zadaná slova, která jsou trií reprezentována, nebo pouze o nějaké jejich prefixy tedy pomocné vrcholy, které žádné z původně zadaných slov nereprezentují. Samozřejmě někde mezi nimi jsou i všechna ta slova, která nás zajímají, nicméně mohlo by se stát, že balastu okolo bude mnoho a jeho přeskakování nám zhorší časovou složitost. Proto si ještě spočítáme funkci f, která pro vrchol v bude udávat nejdelší řetězec u různý od v takový, že u je reprezentováno v trii a dá se k němu dostat z v po zpětné funkci. Tato funkce bude dělat přesně to, co chceme f (v), f (f (v)), atd. jsou právě všechna slova z původní množiny, končící na dané pozici. Spočítat f je snadné postupujeme od nejkratších slov a využijeme toho, že f (v) = f(v) pokud f(v) je reprezentováno v trii a f (v) = f (f(v)) jinak. Toto lze také zřejmě provést v čase O(S). Tím jsme dokončili konstrukci automatu. Nyní zbývá ještě vysvětlit, jak takto získaný automat použít. Jak jsme řekli v úvodu, automat nám umožňuje rychle nalézt pro libovolný text všechna slova s i, která jsou jeho podřetězcem. Označme si prohledávaný text t. Pro každý počáteční úsek zadaného textu (slova) t bychom chtěli najít nejdelší suffix tohoto úseku, který je v trii obsažen (pak můžeme s použitím funkce f snadno nalézt všechna s i, která jsou suffixem libovolného počátečního úseku). Tyto suffixy postupně spočítáme pro počáteční úsek t délky 0, 1, 2, atd. Označme l(i) hledaný suffix pro úsek délky i. Počáteční úsek t délky 0 je prázdné slovo a tedy l(0) = λ. Nechť jsme již spočítali l pro délku i a l(i) = s. Nechť písmeno na (i + 1)-ní pozici v t je x. l(i + 1) má být nejdelší řetězec obsažený v trii, který se vyskytuje jako podřetězec t končící na pozici i + 1, tedy l(i + 1) musí končit na x. l(i + 1) si tedy můžeme napsat jako rx pro nějaký řetězec r, který je také obsažen v trii. Navíc r musí to být suffix s. Projít všechny suffixy s už umíme stačí projít s, f(s), f(f(s)), atd. Mezi nimi hledáme nejdelší, který se dá rozšířit o x tak, abychom zůstali v trii. Všimněme si, že nejdelší takový suffix musí byť první, na který narazíme. Toto opakujeme, dokud nezpracujeme celý řetězec t. Podobný postup jsme již prováděli při konstrukci zpětné funkce, proto nás asi nepřekvapí, že i zde dosáhneme lineární časové složitosti: s se posune směrem od kořene nanejvýš t -krát (v každém kroku o jednu), tedy směrem ke kořeni se můžeme pohnout také nejvýše t -krát. Celková časová složitost je tedy O(t). Pro každou počáteční úsek s textu si navíc označíme slova ze zadání, která jsou jeho suffixy. Jak jsme si již rozmysleli, jsou to právě slova f (s), f (f (s)), atd., plus případně slovo s, je-li jedním ze zadaných. Chtěli bychom, aby nám na vypisování výstupu stačila časová složitost O(délka výstupu). To by se nám mohlo pokazit, pokud by se nějaké slovo r v textu vyskytovalo mnohokrát pak totiž budeme mnohokrát zbytečně procházet posloupnost slov f (r), f (f (r)),.... To snadno napravíme tak, že jakmile narazíme na označené slovo, dál se již funkcí f vracet nebudeme víme totiž, že všechna další slova, ke kterým bychom se takto mohli dostat, jsme již vypsali, když jsme zde byli poprvé. Takto každé vypsané slovo navštívíme právě jednou, a tedy dosáhneme požadované časové složitosti. 5
6 Celková složitost řešení zadané úlohy je O(S + délka výstupu). To je zjevně optimální, protože minimálně musíme načíst vstup a vypsat výsledek. Paměťová složitost je O(S). program Phylogenetics; type plist = ^List; { typ pro seznam organismů } List = record code : string; organism : integer; next : plist; type Base = (ba, bc, bg, bt); ptrienode = ^TrieNode; { typ pro vrchol trie } TrieNode = record sons : array[base] of ptrienode; { větve odpovídající jednotlivým písmenům } back : ptrienode; { zpětná funkce } backinset : ptrienode; { zpětná funkce iterovaná až k prvnímu vrcholu reprezentujícímu organismus } organism : integer; { číslo organismu representovaného vrcholem seen : integer; nebo 0, pokud takový není } { byl-li již tento organismus vypsán při prohledávání jeho potomka, číslo tohoto potomka } next : ptrienode; { následující vrchol trie ve frontě } function BaseToNumber(ch : char) : Base; { převede znaky ACGT na hodnoty typu Base } case ch of A : BaseToNumber := ba; C : BaseToNumber := bc; G : BaseToNumber := bg; T : BaseToNumber := bt; function BaseToChar(b : Base) : char; { převede hodnotu typu base na znaky ACGT } case b of ba: BaseToChar := A ; bc: BaseToChar := C ; bg: BaseToChar := G ; bt: BaseToChar := T ; function NewTrieNode : ptrienode; { vytvoří nový vrchol trie } var ret : ptrienode; i : Base; new (ret); for i := ba to bt do ret^.sons[i] := nil; ret^.back := nil; ret^.backinset := nil; ret^.organism := 0; ret^.seen := 0; NewTrieNode := ret; { přidá suffix řetězce S od pozice P do trie ROOT } procedure AddToTrie(var root : ptrienode; var s : string; p, organism : integer); 6
7 if root = nil then root := NewTrieNode; if p > length (s) then { jsme na konci řetězce } root^.organism := organism; end else { přidáme organismus do větve určené aktuální bazi } AddToTrie (root^.sons[basetonumber (s[p])], s, p + 1, organism); { spočítá zpětnou funkci pro vrchol V trie, jehož otec je O a do v se dostaneme hranou číslo C. } procedure ComputeBack (v, o : ptrienode; c : Base); var last : ptrienode; repeat last := o; o := o^.back; until (o = nil) or (o^.sons[c] <> nil); if o = nil then v^.back := last else v^.back := o^.sons[c]; if v^.back^.organism = 0 then v^.backinset := v^.back^.backinset else v^.backinset := v^.back; { spočítá zpětnou funkci pro trii s vrcholem R. } procedure ComputeBackFunction (r : ptrienode); var queue : ptrienode; queueend : ptrienode; son : ptrienode; c : Base; r^.back := nil; queue := r; queue^.next := nil; queueend := queue; repeat for c := ba to bt do son := queue^.sons[c]; if son <> nil then ComputeBack (son, queue, c); queueend^.next := son; queueend := son; queueend^.next := nil; queue := queue^.next; until queue = nil; 7
8 { vytvoří vyhledávací automat ze zadaného seznamu řetězců } function CreateAutomaton (l : plist) : ptrienode; var root, head : ptrienode; i : integer; root := nil; while l <> nil do AddToTrie (root, l^.code, 1, l^.organism); l := l^.next; root^.back := nil; ComputeBackFunction (root); CreateAutomaton := root; procedure FindAncestors (o : plist; a : ptrienode); { nalezne všechny předky organismu O } var i : integer; v, son : ptrienode; for i := 1 to length (o^.code) do while (a^.back <> nil) and (a^.sons[basetonumber (o^.code[i])] = nil) do a := a^.back; son := a^.sons[basetonumber (o^.code[i])]; if son <> nil then a := son; if a^.organism = 0 then v := a^.backinset else v := a; while (v <> nil) and (v^.seen <> o^.organism) do if v^.organism <> o^.organism then writeln (v^.organism,, o^.organism); v^.seen := o^.organism; v := v^.backinset; { nalezne všechny předky organismu v seznamu L } procedure FindAllAncestors (l : plist; a : ptrienode); while l <> nil do FindAncestors (l, a); l := l^.next; function ReadOrganisms : plist; { načte seznam organismů } var ret, act : plist; i : integer; ret := nil; i := 1; while not eof do new (act); readln (act^.code); 8
9 act^.organism := i; inc (i); act^.next := ret; ret := act; ReadOrganisms := ret; procedure DumpAuto(x : ptrienode; indent : integer); { vypíše automat odsazený o indent mezer } procedure ind; var j : integer; for j := 1 to indent do write ( ); var i : Base; ind; writeln ( node, integer(x)); ind; writeln ( organism, x^.organism); ind; writeln ( back, integer(x^.back)); ind; writeln ( backinset, integer(x^.backinset)); writeln; for i := ba to bt do if (x^.sons[i] <> nil) and (x^.sons[i] <> x) then ind; writeln ( sub, basetochar (i)); DumpAuto (x^.sons[i], indent + 4); var organisms : plist; automaton : ptrienode; organisms := ReadOrganisms; automaton := CreateAutomaton (organisms); { DumpAuto(automaton, 0); } FindAllAncestors (organisms, automaton); end. P-I-4 ALIK a) Úlohu budeme řešit podobně jako Příklad 2 ze studijního textu postupným převáděním na stále jednodušší problémy. Bez újmy na obecnosti budeme předpokládat, že velikost vstupu N je mocnina dvojky (kdyby nebyla, doplníme si vstup nulami, čímž se výsledek evidentně nezmění a N se maximálně zdvojnásobí). Výpočet rozdělíme na fáze, přičemž na konci i-té fáze budou bity registru y pomyslně rozděleny na bloky o 2 i bitech a v každém bloku bude uložen počet jedničkových bitů v odpovídajícím bloku vstupu. Takové číslo se jistě do 2 i bitů vejde, protože 2 i > i pro každé i. Hodnotu registru y na konci i-té fáze si označme y i. Počáteční y 0 je rovno vstupu x, protože každý bit obsahuje počet jedniček v sobě samém. Pro i = log 2 N dostaneme požadovaný výsledek, neboť y i se bude skládat z jediného bloku, v němž bude uložen počet jedniček v celém vstupním čísle. Stačí tedy vyřešit, jak z y i spočíst y i+1 : Každý velký blok v y i+1 obsahuje součet dvou malých bloků poloviční velikosti v y i, které leží na místě horní, resp. spodní poloviny velkého bloku. Proto stačí posunout si vyšší z malých bloků na pozici nižšího a oba sečíst. To můžeme provést pro všechny velké bloky najednou následujícím programem: (b j zde značí jednotlivé malé bloky velikosti b = 2 i, B j jsou výsledné velké bloky velikosti B = 2b = 2 i+1 ) y = b 0 b 1... b N/b 1 = y i p := y (0 b 1 b ) N/B p = 0 b b 1 0 b b b b N/b 1 q := (y >> b) (0 b 1 b ) N/B q = 0 b b 0 0 b b b b N/b 2 y := p + q y = B 0 B 1... B N/B 1 = y i+1 Jednu fázi tedy provedeme v konstantním čase. Celý program proto proběhne v čase O(log N) s registry délky O(N). Ukázka výpočtu pro vstup délky 8: x = y := x y = = y 0 p := y p = q := (y >> 1) q =
10 y := p + q y = = y 1 p := y p = q := (y >> 2) q = y := p + q y = = y 2 p := y p = q := (y >> 4) q = y := p + q y = = y 3 b) Nechť zadané číslo x, ke kterému máme najít nejbližší vyšší číslo y se stejným počtem jedniček, obsahuje alespoň jednu jedničku (pokud ne, hledané y neexistuje a my můžeme vydat libovolný výsledek). Najdeme-li v x poslední souvislý úsek jedniček (může to být i jediná jednička), musí před ním být 0 (v opačném případě je x nejvyšší číslo s daným počtem jedniček a y opět neexistuje). Číslo x tedy lze zapsat ve tvaru α01 k 0 l. Ukážeme, že hledané číslo y bude rovno číslu q = α10 l+1 1 k 1 : 1. q obsahuje stejný počet jedniček jako x. 2. q > x pro každá α, β, γ, kde β a γ mají stejnou délku, je totiž α1β > α0γ. 3. Mezi x a q již žádné číslo se stejným počtem jedniček není každé číslo mezi totiž musí buďto vzniknout z x zvyšením části 0 l, čímž by přibyly přespočetné jedničky, nebo z q snížením části 1 k 1, a tehdy by jedniček příliš ubylo. Jak ale číslo q zkonstruovat? Nejprve postupem podobným jako v Příkladu 1 spočítáme několik pomocných hodnot: x = α01 k 1 10 l a := x 1 a = α01 k 1 01 l b := x a b = α01 k 1 11 l c := x a c = α01 k 1 00 l d := b + 1 d = α10 k 1 00 l e := c d e = 11 k 1 00 l = 1 k 0 l+1 f := (e 1) e f = 1 k 1 0 l+2 Nyní by stačilo jedničky v f posunout k pravému okraji čísla a zkombinovat s jedničkami v d a dostali bychom kýžené číslo q. Operace >> to ale sama o sobě nedokáže, neboť posunutí nemáme dáno počtem bitů, nýbrž podmínkou první jednička se dotkne okraje. Znovu na to půjdeme postupným zjednodušováním problému a budeme bez újmy na obecnosti předpokládat, že N je mocnina dvojky. Fáze si tentokrát očíslujeme pozpátku: od log 2 N-té po nultou. V i-té fázi zařídíme, aby f končilo na méně než 2 i nul. Opět v počáteční fázi nemáme co na práci a v koncové dostaneme očekávaný výsledek. Ostatní fáze budou fungovat takto: dostaneme f, které končí na nejvýše 2 i+1 nul a potřebujeme ho posunout doprava tak, aby končilo na nejvýše 2 i nul. Stačí se tedy podívat, zda je nejnižších 2 i bitů nulových, a pokud ano, f posunout doprava o 2 i míst. To lze provést například pomocí konstrukce r := if (s, t, u) z Příkladu 2: g := f 1 2i g = dolních 2 i bitů f i+1 h := if (g, 0, 2 i ) h = o kolik posouváme f := f >> h f = výsledek i-té fáze f i Po poslední fázi zakončíme: y := d f d = α10 k 1 00 l f = 00 l+1 1 k 1 y = α10 l+1 1 k 1 a jsme hotovi. Trvalo nám to celkem O(log N) kroků (konstantně mnoho na inicializaci, na konečný výpočet y a rovněž na každou fázi), potřebovali jsme registry o O(N) bitech. Příklad výpočtu pro N = 8: x = a := x 1 a = b := x a b = c := x a c = d := b + 1 d = e := c d e = f := (e 1) e f = = f 3 g := f g = 0000 h := if (g, 0, 2 2 ) h = f := f >> h f = = f 2 g := f g = 10 h := if (g, 0, 2 1 ) h = f := f >> h f = = f 1 g := f g = 0 10
11 h := if (g, 0, 2 0 ) h = f := f >> h f = = f 0 y := d f y =
1. D Y N A M I C K É DAT O V É STRUKTUR Y
1. D Y N A M I C K É DAT O V É STRUKTUR Y Autor: Petr Mik Abychom se mohli pustit do dynamických datových struktur, musíme se nejdřív podívat na datový typ ukazatel. 1. D AT O V Ý TYP U K A Z AT E L Datové
Hledání v textu algoritmem Boyer Moore
Zápočtová práce z Algoritmů a Datových Struktur II (NTIN061) Hledání v textu algoritmem Boyer Moore David Pěgřímek http://davpe.net Algoritmus Boyer Moore[1] slouží k vyhledání vzoru V v zadaném textu
Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010
Dynamické programování Jiří Vyskočil, Marko Genyg-Berezovskyj 2010 Rozděl a panuj (divide-and-conquer) Rozděl (Divide): Rozděl problém na několik podproblémů tak, aby tyto podproblémy odpovídaly původnímu
Stromy, haldy, prioritní fronty
Stromy, haldy, prioritní fronty prof. Ing. Pavel Tvrdík CSc. Katedra počítačů FEL České vysoké učení technické DSA, ZS 2008/9, Přednáška 6 http://service.felk.cvut.cz/courses/x36dsa/ prof. Pavel Tvrdík
Základní datové struktury III: Stromy, haldy
Základní datové struktury III: Stromy, haldy prof. Ing. Pavel Tvrdík CSc. Katedra počítačových systémů Fakulta informačních technologií České vysoké učení technické v Praze c Pavel Tvrdík, 2010 Efektivní
68. ročník Matematické olympiády 2018/2019
68. ročník Matematické olympiády 2018/2019 Řešení úloh krajského kola kategorie P P-II-1 Tulipány Budeme řešit o něco obecnější úlohu: dovolíme si předepsat, zda má na n-té pozici být tulipán, a pokud
V každém kroku se a + b zmenší o min(a, b), tedy vždy alespoň o 1. Jestliže jsme na začátku dostali 2
Euklidův algoritmus Doprovodný materiál pro cvičení Programování I. NPRM044 Autor: Markéta Popelová Datum: 31.10.2010 Euklidův algoritmus verze 1.0 Zadání: Určete největšího společného dělitele dvou zadaných
Obecná informatika. Matematicko-fyzikální fakulta Univerzity Karlovy v Praze. Podzim 2012
Obecná informatika Přednášející Putovních přednášek Matematicko-fyzikální fakulta Univerzity Karlovy v Praze Podzim 2012 Přednášející Putovních přednášek (MFF UK) Obecná informatika Podzim 2012 1 / 18
1 PRVOCISLA: KRATKY UKAZKOVY PRIKLAD NA DEMONSTRACI BALIKU WEB 1
1 PRVOCISLA: KRATKY UKAZKOVY PRIKLAD NA DEMONSTRACI BALIKU WEB 1 1. Prvocisla: Kratky ukazkovy priklad na demonstraci baliku WEB. Nasledujici program slouzi pouze jako ukazka nekterych moznosti a sluzeb,
68. ročník Matematické olympiády 2018/2019
68. ročník Matematické olympiády 2018/2019 Řešení úloh ústředního kola kategorie P 2. soutěžní den P-III-4 Výlet Abychom našli požadovaný výlet délky 4, stačí najít dvě hvězdy a a b, které mají dva společné
Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.
Vyhledávání doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava Prezentace ke dni 21. září 2018 Jiří Dvorský (VŠB TUO) Vyhledávání 242 / 433 Osnova přednášky
Výhody a nevýhody jednotlivých reprezentací jsou shrnuty na konci kapitoly.
Kapitola Reprezentace grafu V kapitole?? jsme se dozvěděli, co to jsou grafy a k čemu jsou dobré. rzo budeme chtít napsat nějaký program, který s grafy pracuje. le jak si takový graf uložit do počítače?
DobSort. Úvod do programování. DobSort Implementace 1/3. DobSort Implementace 2/3. DobSort - Příklad. DobSort Implementace 3/3
DobSort Úvod do programování Michal Krátký 1,Jiří Dvorský 1 1 Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programování, 2004/2005 V roce 1980 navrhl Dobosiewicz variantu (tzv. DobSort),
INFORMATIKA. Vybrané podposloupnosti
INFORMATIKA Vybrané podposloupnosti (Úlohy z MO kategorie P, 30. část) PAVEL TÖPFER Matematicko-fyzikální fakulta UK, Praha V našem seriálu putujícím po zajímavých úlohách Matematické olympiády - kategorie
Binární vyhledávací stromy
Binární vyhledávací stromy Definice: Binární vyhledávací strom (po domácku BVS) je buďto prázdná množina nebo kořen obsahující jednu hodnotu a mající dva podstromy (levý a pravý), což jsou opět BVS, ovšem
54. ročník Matematické olympiády 2004/2005
54. ročník Matematické olympiády 2004/2005 Řešení úloh krajského kola kategorie P P-II-1 Prádelní salón Při řešení této úlohy použijeme řešení úlohy P-I-1 Prádelna z domácího kola. Jedinou změnou oproti
Binární soubory (datové, typované)
Binární soubory (datové, typované) - na rozdíl od textových souborů data uložena binárně (ve vnitřním tvaru jako v proměnných programu) není čitelné pro člověka - všechny záznamy téhož typu (může být i
Algoritmus pro hledání nejkratší cesty orientovaným grafem
1.1 Úvod Algoritmus pro hledání nejkratší cesty orientovaným grafem Naprogramoval jsem v Matlabu funkci, která dokáže určit nejkratší cestu v orientovaném grafu mezi libovolnými dvěma vrcholy. Nastudoval
Intervalové stromy. Představme si, že máme posloupnost celých čísel p 0, p 1,... p N 1, se kterou budeme. 1. Změna jednoho čísla v posloupnosti.
Intervalové stromy Představme si, že máme posloupnost celých čísel p 0, p 1,... p N 1, se kterou budeme průběžně provádět tyto dvě operace: 1. Změna jednoho čísla v posloupnosti. 2. Zjištění součtu čísel
12. Lineární programování
. Lineární programování. Lineární programování Úloha lineárního programování (lineární optimalizace) je jedním ze základních problémů teorie optimalizace. Našim cílem je nalézt maximum (resp. minimum)
Metodický koncept k efektivní podpoře klíčových odborných kompetencí s využitím cizího jazyka ATCZ62 - CLIL jako výuková strategie na vysoké škole
Pattern matching Metodický koncept k efektivní podpoře klíčových odborných kompetencí s využitím cizího jazyka ATCZ62 - CI jako výuková strategie na vysoké škole Pattern matching porovnávání vzorů Hledání
Binární vyhledávací stromy pokročilé partie
Binární vyhledávací stromy pokročilé partie KMI/ALS lekce Jan Konečný 30.9.204 Literatura Cormen Thomas H., Introduction to Algorithms, 2nd edition MIT Press, 200. ISBN 0-262-5396-8 6, 3, A Knuth Donald
Algoritmy na ohodnoceném grafu
Algoritmy na ohodnoceném grafu Dvě základní optimalizační úlohy: Jak najít nejkratší cestu mezi dvěma vrcholy? Dijkstrův algoritmus s t Jak najít minimální kostru grafu? Jarníkův a Kruskalův algoritmus
57. ročník Matematické olympiády 2007/2008
57. ročník Matematické olympiády 2007/200 Řešení úloh domácího kola kategorie P P-I-1 O zdánlivém kopci Úkolem je vybrat ze zadané posloupnosti co nejdelší podposloupnost, která by nejprve rostla a potom
Časová a prostorová složitost algoritmů
.. Časová a prostorová složitost algoritmů Programovací techniky doc. Ing. Jiří Rybička, Dr. ústav informatiky PEF MENDELU v Brně rybicka@mendelu.cz Hodnocení algoritmů Programovací techniky Časová a prostorová
Digitální učební materiál
Digitální učební materiál Číslo projektu: CZ.1.07/1.5.00/34.0548 Název školy: Gymnázium, Trutnov, Jiráskovo náměstí 325 Název materiálu: VY_32_INOVACE_145_IVT Autor: Ing. Pavel Bezděk Tematický okruh:
5 Orientované grafy, Toky v sítích
Petr Hliněný, FI MU Brno, 205 / 9 FI: IB000: Toky v sítích 5 Orientované grafy, Toky v sítích Nyní se budeme zabývat typem sít ových úloh, ve kterých není podstatná délka hran a spojení, nýbž jejich propustnost
Suffixové stromy. Osnova:
Suffixové stromy http://jakub.kotrla.net/suffixtrees/ Osnova: Motivační příklad Přehled možných řešení Definice suffixového stromu Řešení pomocí suffixových stromů Konstrukce suffixového stromu Další použití,
Standardní algoritmy vyhledávací.
Standardní algoritmy vyhledávací. Vyhledávací algoritmy v C++ nám umožňují vyhledávat prvky v datových kontejnerech podle různých kritérií. Také se podíváme na vyhledávání metodou půlením intervalu (binární
68. ročník Matematické olympiády 2018/2019
68. ročník Matematické olympiády 2018/2019 Řešení úloh ústředního kola kategorie P 1. soutěžní den P-III-1 Půl království Pokud v hledané polorovině neleží všechny zadané body, můžeme bez újmy na obecnosti
Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem
Test prvočíselnosti Úkol: otestovat dané číslo N, zda je prvočíslem 1. zkusit všechny dělitele od 2 do N-1 časová složitost O(N) cca N testů 2. stačí zkoušet všechny dělitele od 2 do N/2 (větší dělitel
Informatika navazující magisterské studium Přijímací zkouška z informatiky 2018 varianta A
Informatika navazující magisterské studium Přijímací zkouška z informatiky 2018 varianta A Každá úloha je hodnocena maximálně 25 body. Všechny své odpovědi zdůvodněte! 1. Postavte na stůl do řady vedle
Algoritmy I, složitost
A0B36PRI - PROGRAMOVÁNÍ Algoritmy I, složitost České vysoké učení technické Fakulta elektrotechnická v 1.01 Rychlost... Jeden algoritmus (program, postup, metoda ) je rychlejší než druhý. Co ta věta znamená??
Programovací jazyk Pascal
Programovací jazyk Pascal Syntaktická pravidla (syntaxe jazyka) přesná pravidla pro zápis příkazů Sémantická pravidla (sémantika jazyka) pravidla, která každému příkazu přiřadí přesný význam Všechny konstrukce
Naproti tomu gramatika je vlastně soupis pravidel, jak
1 Kapitola 1 Úvod V přednášce se zaměříme hlavně na konečný popis obecně nekonečných množin řetězců symbolů dané množiny A. Prvkům množiny A budeme říkat písmena, řetězcům (konečným posloupnostem) písmen
Dijkstrův algoritmus
Dijkstrův algoritmus Hledání nejkratší cesty v nezáporně hranově ohodnoceném grafu Necht je dán orientovaný graf G = (V, H) a funkce, která každé hraně h = (u, v) H přiřadí nezáporné reálné číslo označované
FIT ČVUT MI-LOM Lineární optimalizace a metody. Dualita. Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti
FIT ČVUT MI-LOM Lineární optimalizace a metody Dualita Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti Michal Černý, 2011 FIT ČVUT, MI-LOM, M. Černý, 2011: Dualita 2/5 Dualita Evropský
Implementace LL(1) překladů
Překladače, přednáška č. 6 Ústav informatiky, FPF SU Opava sarka.vavreckova@fpf.slu.cz Poslední aktualizace: 30. října 2007 Postup Programujeme syntaktickou analýzu: 1 Navrhneme vhodnou LL(1) gramatiku
NPRG030 Programování I, 2018/19 1 / :03:07
NPRG030 Programování I, 2018/19 1 / 20 3. 12. 2018 09:03:07 Vnitřní třídění Zadání: Uspořádejte pole délky N podle hodnot prvků Měřítko efektivity: * počet porovnání * počet přesunů NPRG030 Programování
63. ročník Matematické olympiády 2013/2014
63. ročník Matematické olympiády 2013/2014 Úlohy ústředního kola kategorie P 2. soutěžní den Na řešení úloh máte 4,5 hodiny čistého času. Při soutěži je zakázáno používat jakékoliv pomůcky kromě psacích
Lineární spojový seznam (úvod do dynamických datových struktur)
Lineární spojový seznam (úvod do dynamických datových struktur) Jan Hnilica Počítačové modelování 11 1 Dynamické datové struktury Definice dynamické struktury jsou vytvářeny za běhu programu z dynamicky
Úvod do programování
Úvod do programování Základní literatura Töpfer, P.: Algoritmy a programovací techniky, Prometheus, Praha učebnice algoritmů, nikoli jazyka pokrývá velkou část probíraných algoritmů Satrapa, P.: Pascal
Základy algoritmizace. Pattern matching
Základy algoritmizace Pattern matching 1 Pattern matching Úloha nalézt v nějakém textu výskyty zadaných textových vzorků patří v počítačové praxi k nejfrekventovanějším. Algoritmy, které ji řeší se používají
Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.
Vyhledávání doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava Prezentace ke dni 12. září 2016 Jiří Dvorský (VŠB TUO) Vyhledávání 201 / 344 Osnova přednášky
1 Linearní prostory nad komplexními čísly
1 Linearní prostory nad komplexními čísly V této přednášce budeme hledat kořeny polynomů, které se dále budou moci vyskytovat jako složky vektorů nebo matic Vzhledem k tomu, že kořeny polynomu (i reálného)
Vzdálenost uzlů v neorientovaném grafu
Vzdálenosti a grafy Vzdálenost uzlů v neorientovaném grafu Je dán neorientovaný neohodnocený graf G = (V,E,I) vzdálenost uzlů u a v v neorientovaném souvislém grafu G je délka nejkratší cesty spojující
PQ-stromy a rozpoznávání intervalových grafů v lineárním čase
-stromy a rozpoznávání intervalových grafů v lineárním čase ermutace s předepsanými intervaly Označme [n] množinu {1, 2,..., n}. Mějme permutaci π = π 1, π 2,..., π n množiny [n]. Řekneme, že množina S
Hranová konzistence. Arc consistency AC. Nejprve se zabýváme binárními CSP. podmínka odpovídá hraně v grafu podmínek
Hranová konzistence Arc consistency AC Nejprve se zabýváme binárními CSP podmínka odpovídá hraně v grafu podmínek Hrana (V i, V j ) je hranově konzistentní, právě když pro každou hodnotu x z aktuální domény
- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku
Znaky - standardní typ char var Z, W: char; - znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku - v TP (často i jinde) se používá kódová
Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu
Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu Ukazatel a dynamické datové struktury v prostředí DELPHI Důležitým termínem a konstrukčním programovým prvkem je typ UKAZATEL. Je to vlastně
Union-Find problém. Kapitola 1
Kapitola 1 Union-Find problém Motivace: Po světě se toulá spousta agentů. Často se stává, že jeden agent má spoustu jmen/přezdívek, které používá například při rezervaci hotelu, restaurace, na návštěvě
Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz
Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz (2 + 5) * (13-4) * + - 2 5 13 4 - listy stromu obsahují operandy (čísla) - vnitřní uzly obsahují operátory (znaménka)
Dokumentace programu piskvorek
Dokumentace programu piskvorek Zápočtového programu z Programování II PRM045 Ondřej Vostal 20. září 2011, Letní semestr, 2010/2011 1 Stručné zadání Napsat textovou hru piškvorky se soupeřem s umělou inteligencí.
Rekurze. Pavel Töpfer, 2017 Programování 1-8 1
Rekurze V programování ve dvou hladinách: - rekurzivní algoritmus (řešení úlohy je definováno pomocí řešení podúloh stejného charakteru) - rekurzivní volání procedury nebo funkce (volá sama sebe přímo
Základy algoritmizace a programování
Základy algoritmizace a programování Složitost algoritmů. Třídění Přednáška 8 16. listopadu 2009 Který algoritmus je "lepší"? Různé algoritmy, které řeší stejnou úlohu zbytek = p % i; zbytek = p - p/i*i;
5 Rekurze a zásobník. Rekurzivní volání metody
5 Rekurze a zásobník Při volání metody z metody main() se do zásobníku uloží aktivační záznam obsahující - parametry - návratovou adresu, tedy adresu, kde bude program pokračovat v metodě main () po skončení
8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek
8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek 1/41 Základní příkazy Všechny příkazy se píšou malými písmeny! Za většinou příkazů musí být středník (;)! 2/41 Základní příkazy
Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague
1 / 23 Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague 2 / 23 biologové často potřebují najít často se opakující sekvence DNA tyto sekvence bývají relativně krátké,
Zdůvodněte, proč funkce n lg(n) roste alespoň stejně rychle nebo rychleji než než funkce lg(n!). Symbolem lg značíme logaritmus o základu 2.
1 3 4 5 6 7 8 9 10 11 1 13 14 15 16 17 18 19 0 1 3 4 5 6 7 8 9 30 31 3 Zdůvodněte, proč funkce f(n) = n log(n) 1 n 1/ roste rychleji než funkce g(n) = n. Zdůvodněte, proč funkce f(n) = n 3/ log(n) roste
Dynamické programování
Dynamické programování Rekurzivní funkce je taková funkce, která při svém běhu volá sama sebe, často i více než jednou, což v důsledku může vést na exponenciální algoritmus. Dynamické programování je technika,
1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:
1. lekce 1. Minimální program do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme: #include #include int main() { printf("hello world!\n"); return 0; 2.
Jednoduché cykly 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45.
Jednoduché cykly Tento oddíl obsahuje úlohy na první procvičení práce s cykly. Při řešení každé ze zde uvedených úloh stačí použít vedle podmíněných příkazů jen jediný cyklus. Nepotřebujeme používat ani
Definice. Vektorový prostor V nad tělesem T je množina s operacemi + : V V V, tj. u, v V : u + v V : T V V, tj. ( u V )( a T ) : a u V které splňují
Definice. Vektorový prostor V nad tělesem T je množina s operacemi + : V V V, tj. u, v V : u + v V : T V V, tj. ( u V )( a T ) : a u V které splňují 1. u + v = v + u, u, v V 2. (u + v) + w = u + (v + w),
Stromy. Jan Hnilica Počítačové modelování 14
Stromy Jan Hnilica Počítačové modelování 14 1 Základní pojmy strom = dynamická datová struktura, složená z vrcholů (uzlů, prvků) propojených hranami hrany chápeme jako orientované, tzn. vedou z uzlu A
Vrcholová barevnost grafu
Vrcholová barevnost grafu Definice: Necht G = (V, E) je obyčejný graf a k N. Zobrazení φ : V {1, 2,..., k} nazýváme k-vrcholovým obarvením grafu G. Pokud φ(u) φ(v) pro každou hranu {u, v} E, nazveme k-vrcholové
Sada 1 - Základy programování
S třední škola stavební Jihlava Sada 1 - Základy programování 17. Řadící algoritmy Digitální učební materiál projektu: SŠS Jihlava šablony registrační číslo projektu:cz.1.09/1.5.00/34.0284 Šablona: III/2
Stromové rozklady. Definice 1. Stromový rozklad grafu G je dvojice (T, β) taková, že T je strom,
Stromové rozklady Zdeněk Dvořák 25. října 2017 Definice 1. Stromový rozklad grafu G je dvojice (T, β) taková, že T je strom, β je funkce přiřazující každému vrcholu T podmnožinu vrcholů v G, pro každé
Dynamické datové struktury III.
Dynamické datové struktury III. Halda. Tomáš Bayer bayertom@natur.cuni.cz Katedra aplikované geoinformatiky a kartografie, Přírodovědecká fakulta UK. Tomáš Bayer bayertom@natur.cuni.cz (Katedra aplikované
Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39
Základy algoritmizace Michal Krátký 1, Jiří Dvorský 1 1 Katedra informatiky VŠB Technická univerzita Ostrava Základy algoritmizace, 2006/2007 Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39
3. Prohledávání grafů
3. Prohledávání grafů Prohledání do šířky Breadth-First Search BFS Jde o grafový algoritmus, který postupně prochází všechny vrcholy v dané komponentě souvislosti. Algoritmus nejprve projde všechny sousedy
a počtem sloupců druhé matice. Spočítejme součin A.B. Označme matici A.B = M, pro její prvky platí:
Řešené příklady z lineární algebry - část 1 Typové příklady s řešením Příklady jsou určeny především k zopakování látky před zkouškou, jsou proto řešeny se znalostmi učiva celého semestru. Tento fakt se
Řešení: PŘENESVĚŽ (N, A, B, C) = přenes N disků z A na B pomocí C
Hanojské věže - 3 kolíky A, B, C - na A je N disků různé velikosti, seřazené od největšího (dole) k nejmenšímu (nahoře) - kolíky B a C jsou prázdné - úkol: přenést všechny disky z A na B, mohou se odkládat
Hledáme efektivní řešení úloh na grafu
Hledáme efektivní řešení úloh na grafu Mějme dán graf následující úlohy: G = ( V, E), chceme algoritmicky vyřešit Je daný vrchol t dosažitelný z vrcholu s? Pokud ano, jaká nejkratší cesta tyto vrcholy
Už známe datové typy pro representaci celých čísel i typy pro representaci
Dlouhá čísla Tomáš Holan, dlouha.txt, Verse: 19. února 2006. Už známe datové typy pro representaci celých čísel i typy pro representaci desetinných čísel. Co ale dělat, když nám žádný z dostupných datových
Algoritmy a datové struktury
Algoritmy a datové struktury Stromy 1 / 32 Obsah přednášky Pole a seznamy Stromy Procházení stromů Binární stromy Procházení BS Binární vyhledávací stromy 2 / 32 Pole Hledání v poli metodou půlení intervalu
Zpracoval: hypspave@fel.cvut.cz 7. Matematická indukce a rekurse. Řešení rekurentních (diferenčních) rovnic s konstantními koeficienty.
Zpracoval: hypspave@fel.cvut.cz 7. Matematická indukce a rekurse. Řešení rekurentních (diferenčních) rovnic s konstantními koeficienty. (A7B01MCS) I. Matematická indukce a rekurse. Indukční principy patří
Náplň. v.0.03 16.02.2014. - Jednoduché příklady na práci s poli v C - Vlastnosti třídění - Způsoby (algoritmy) třídění
Náplň v.0.03 16.02.2014 - Jednoduché příklady na práci s poli v C - Vlastnosti třídění - Způsoby (algoritmy) třídění Spojení dvou samostatně setříděných polí void Spoj(double apole1[], int adelka1, double
1.1 Struktura programu v Pascalu Vstup a výstup Operátory a některé matematické funkce 5
Obsah Obsah 1 Programovací jazyk Pascal 1 1.1 Struktura programu v Pascalu.................... 1 2 Proměnné 2 2.1 Vstup a výstup............................ 3 3 Operátory a některé matematické funkce 5
doplněk, zřetězení, Kleeneho operaci a reverzi. Ukážeme ještě další operace s jazyky, na které je
28 [181105-1236 ] 2.7 Další uzávěrové vlastnosti třídy regulárních jazyků Z předchozích přednášek víme, že třída regulárních jazyků je uzavřena na sjednocení, průnik, doplněk, zřetězení, Kleeneho operaci
Konstrukce relace. Postupně konstruujeme na množině všech stavů Q relace i,
[161014-1204 ] 11 2.1.35 Konstrukce relace. Postupně konstruujeme na množině všech stavů Q relace i, kde i = 0, 1,..., takto: p 0 q právě tehdy, když bud p, q F nebo p, q F. Dokud i+1 i konstruujeme p
4 Stromy a les. Definice a základní vlastnosti stromů. Kostry grafů a jejich počet.
4 Stromy a les Jedním ze základních, a patrně nejjednodušším, typem grafů jsou takzvané stromy. Jedná se o souvislé grafy bez kružnic. Přes svou (zdánlivou) jednoduchost mají stromy bohatou strukturu a
NPRG030 Programování I, 2017/18 1 / :22:16
NPRG030 Programování I, 2017/18 1 / 26 20. 10. 2017 11:22:16 Ordinální typy standardní: integer, char, boolean Vlastnosti ordinálních typů: 1. hodnot je konečný počet a hodnoty jsou uspořádány 2. ke každé
Volné stromy. Úvod do programování. Kořenové stromy a seřazené stromy. Volné stromy
Volné stromy Úvod do programování Souvislý, acyklický, neorientovaný graf nazýváme volným stromem (free tree). Často vynecháváme adjektivum volný, a říkáme jen, že daný graf je strom. Michal Krátký 1,Jiří
1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:
1. lekce 1. Minimální program do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme: #include #include int main() { printf("hello world!\n"); return 0; 2.
IB108 Sada 1, Příklad 1 Vypracovali: Tomáš Krajča (255676), Martin Milata (256615)
IB108 Sada 1, Příklad 1 ( ) Složitost třídícího algoritmu 1/-Sort je v O n log O (n.71 ). Necht n = j i (velikost pole, které je vstupním parametrem funkce 1/-Sort). Lehce spočítáme, že velikost pole předávaná
6 Ordinální informace o kritériích
6 Ordinální informace o kritériích Ordinální informací o kritériích se rozumí jejich uspořádání podle důležitosti. Předpokládejme dále standardní značení jako v předchozích cvičeních. Existují tři základní
Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague
1 / 40 regula Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague regula 1 2 3 4 5 regula 6 7 8 2 / 40 2 / 40 regula Iterační pro nelineární e Bud f reálná funkce
Parametrické programování
Parametrické programování Příklad 1 Parametrické pravé strany Firma vyrábí tři výrobky. K jejich výrobě potřebuje jednak surovinu a jednak stroje, na kterých dochází ke zpracování. Na první výrobek jsou
Kolik existuje různých stromů na pevně dané n-prvkové množině vrcholů?
Kapitola 9 Matice a počet koster Graf (orientovaný i neorientovaný) lze popsat maticí, a to hned několika různými způsoby. Tématem této kapitoly jsou incidenční matice orientovaných grafů a souvislosti
Anotace. Informace o praktiku z programování!!! Direktivy překladače Soubory (textové) Quicksort Metoda rozděl a panuj
Anotace Informace o praktiku z programování!!! Direktivy překladače Soubory (textové) Quicksort Metoda rozděl a panuj Direktivy překladače Překladač kontroluje plno věcí, například: zda nekoukáme za konec
Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015
Programování 3. hodina RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015 Umíme z minulé hodiny Implementace zásobníku a fronty pomocí
bfs, dfs, fronta, zásobník, prioritní fronta, halda
bfs, dfs, fronta, zásobník, prioritní fronta, halda Petr Ryšavý 19. září 2017 Katedra počítačů, FEL, ČVUT prohledávání grafů Proč prohledávání grafů Zkontrolovat, zda je sít spojitá. Hledání nejkratší
53. ročník Matematické olympiády 2003/2004
5. ročník Matematické olympiády 00/004 Úlohy celostátního kola kategorie P. soutěžní den Na řešení úloh máte 4,5 hodiny čistého času. Řešení každého příkladu musí obsahovat: Popis řešení, to znamená slovní
Syntaktická analýza. Implementace LL(1) překladů. Šárka Vavrečková. Ústav informatiky, FPF SU Opava
Implementace LL(1) překladů Ústav informatiky, FPF SU Opava sarka.vavreckova@fpf.slu.cz Poslední aktualizace: 6. ledna 2012 Postup Programujeme syntaktickou analýzu: 1 Navrhneme vhodnou LL(1) gramatiku
66. ročník Matematické olympiády 2016/2017
66. ročník Matematické olympiády 2016/2017 Úlohy ústředního kola kategorie P 1. soutěžní den Na řešení úloh máte 4,5 hodiny čistého času. Řešení každé úlohy pište na samostatný list papíru. Při soutěži
TGH05 - aplikace DFS, průchod do šířky
TGH05 - aplikace DFS, průchod do šířky Jan Březina Technical University of Liberec 31. března 2015 Grafová formulace CPM (critical path method) Orientovaný acyklický graf (DAG) je orientovaný graf neobsahující
4EK213 Lineární modely. 10. Celočíselné programování
4EK213 Lineární modely 10. Celočíselné programování 10.1 Matematický model úlohy ILP Nalézt extrém účelové funkce z = c 1 x 1 + c 2 x 2 + + c n x n na soustavě vlastních omezení a 11 x 1 + a 12 x 2 + a
Základní datové struktury
Základní datové struktury Martin Trnečka Katedra informatiky, Přírodovědecká fakulta Univerzita Palackého v Olomouci 4. listopadu 2013 Martin Trnečka (UPOL) Algoritmická matematika 1 4. listopadu 2013
Algoritmizace a programování
Algoritmizace a programování Vyhledávání, vkládání, odstraňování Vyhledání hodnoty v nesetříděném poli Vyhledání hodnoty v setříděném poli Odstranění hodnoty z pole Vkládání hodnoty do pole Verze pro akademický
Úvod do programování 6. hodina
Úvod do programování 6. hodina RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015 Umíme z minulé hodiny Algoritmy Třídění pole: Selection