diff --git a/tasks.json b/tasks.json index 35a82bb..cb90908 100644 --- a/tasks.json +++ b/tasks.json @@ -89,7 +89,7 @@ "kucharka-zakladni-algoritmus" ], "position": [ - -428.70552825927734, + -427.0237350463867, 385.39715576171875 ], "taskReference": "26-Z2-2", @@ -611,13 +611,15 @@ "type": "open-data", "taskReference": "28-Z1-1", "comment": "triviální, průchod pole", - "requires": [], + "requires": [ + "26-Z2-2" + ], "position": [ - 499.0694875717163, - 1022.1491203308105 + -536.9149789810181, + 485.6571464538574 ], "title": "Kevinův leták", - "hidden": true, + "hidden": false, "points": 8 }, { @@ -812,8 +814,8 @@ "kucharka-zakladni-binarni-vyhledavani" ], "position": [ - -921.8528137207031, - 835.5108184814453 + -1133.7586975097656, + 879.2374420166016 ], "title": "Mocniny", "points": 10 @@ -1321,8 +1323,8 @@ "kucharka-zakladni-prefixove-soucty-2d" ], "position": [ - -710.1918792724609, - 1333.6874084472656 + -573.9666595458984, + 1417.7770080566406 ], "hidden": false, "points": 12 @@ -2034,14 +2036,15 @@ "id": "33-Z1-1", "taskReference": "33-Z1-1", "requires": [ - "28-Z1-1" + "28-Z1-1", + "kucharka-zakladni-fronta-a-zasobnik" ], "position": [ - 629.0449371337891, - 1094.560305595398 + -973.7036590576172, + 1264.421389579773 ], "title": "Kontrola závorkových programů", - "hidden": true, + "hidden": false, "points": 8 }, { @@ -2146,8 +2149,8 @@ "title": "Rozděl a panuj - binární vyhledávání", "htmlContent": "

Rozděl a panuj

Jednou ze základních technik je rozdělení složitějšího problému na menší části, které opět můžeme rozdělit na menší a tak dále, dokud se nedostaneme k problémům tak malým, že je už umíme triviálně vyřešit.

Binární vyhledávání v poli

Představme si, že máme seřazené pole n prvků a chceme zjistit, jestli se v něm nachází prvek s hodnotou k. Určitě můžeme projít celé pole v lineárním čase (tím, že budeme brát jeden prvek za druhým a kontrolovat, zda je roven hodnotě k), ale to je zbytečně pomalé a nevyužívá toho, že máme pole seřazené.

Můžeme totiž začít s velkým problémem a ten postupně zmenšovat na stále menší a menší. Nejdříve hledáme k v celém poli. Podíváme se na jeho prostřední prvek:

Když tímto postupným dělením problémů na menší dojdeme až k poli o velikosti jednoho prvku, stačí tento prvek jenom porovnat, dál už se pole nepokoušíme rozdělovat.

Jelikož se nám každým krokem problém zmenší na polovinu, maximálně po log n krocích se dostaneme na pole velikosti jedna. Říkáme, že algoritmus má logaritmickou časovou složitost, píšeme O(log n). (Pokud není řečeno jinak, znamená pro nás v informatice značka log dvojkový logaritmus, což je funkce opačná k funkci 2n a roste o hodně pomaleji než funkce lineární. Pro velká n platí: 1 < log n < n a například log 2 = 1, log 8 = 3, log 1024 = 10.)

Prakticky postup provádíme tak, že si udržujeme levý a pravý okraj aktuálně zpracovávaného úseku a postupně je k sobě přibližujeme.

FIXME code

Další aplikace

Další typickou aplikací postupu rozděl a panuj je například třídění posloupnosti pomocí Mergesortu. Ten v základu funguje tak, že každou posloupnost, kterou dostane k setřídění, rozdělí na poloviny a každou z nich setřídí rekurzivním zavoláním sebe sama. Zanořování se zastaví ve chvíli, kdy třídíme posloupnost délky jedna (ta už je z podstaty setříděná). Pak jen v každém kroku ze dvou setříděných menších posloupností vyrobí jejich sléváním setříděnou posloupnost dvojnásobné délky.

Více se o metodě Rozděl a panuj můžete dozvědět ve stejnojmenné kuchařce.

", "position": [ - -841.6388244628906, - 755.4090232849121 + -1055.2265319824219, + 787.3630638122559 ] }, { @@ -2258,8 +2261,8 @@ "title": "Dvourozměrné prefixové součty", "htmlContent": "

Dvourozměrné prefixové součty

Prefixové součty se dají zobecnit i do více rozměrů, ale princip je vždy stejný. Například dvourozměrné prefixové součty u matice fungují tak, že si předpočítáme součty podmatic začínajících levým vrchním políčkem a končící na indexu [x,y].

Z toho je vidět, že prefixový součet zpravidla obsadí stejně velký prostor jako původní data, v tomto případě tedy budeme mít matici hodnot prefixových součtů končících na zadaných souřadnicích. Jak ale získat součet nějaké podmatice, která se nachází někde „uprostřed“ naší matice?

Použijeme stejný princip jako u jednorozměrného případu: Přičteme větší část, kterou chceme započítat, a odečteme od ní části, které započítat nechceme. Pro případ podmatice začínající vlevo nahoře na pozici [x,y] a končící napravo dole na [X,Y] to ilustruje následující obrázek:

\"Dvourozměrné

Nejdříve přičteme celý prefixový součet končící na pozici [X,Y]. Tím jsme ale započítali i části A, B a C z obrázku, které započítat nechceme. Tak odečteme prefixové součty končící na indexech [X,y] a [x,Y]. Ale pozor, teď jsme odečetli jednou A+B a jednou A+C, tedy část A (prefixový součet končící na pozici [x,y]) jsme odečetli dvakrát, musíme ji proto ještě jednou přičíst.

Celý vzorec tedy vypadá takto:

soucet = P[X,Y] - P[X,y] - P[x,Y] + P[x,y];

Tento princip přičítání a odečítání se dá zobecnit i pro libovolné vyšší rozměry, ale chce to již trošku představivosti, co se má přičíst a kolikrát. Říká se tomu také princip inkluze a exkluze a najde použití nejen u vícerozměrných prefixových součtů.

", "position": [ - -710.7839622497559, - 1225.3379516601562 + -577.9223289489746, + 1311.1093139648438 ] }, {