"htmlContent":"<h3>Rozděl a panuj</h3><p>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.</p><h4>Binární vyhledávání v poli</h4><p>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é.</p><p>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:</p><ul><li>Pokud je roven k, jsme hotovi.</li><li>Je-li větší než k, víme, že se k musí nacházet nalevo od něj. Můžeme tedy hledat znovu, ale tentokrát se omezit jen na levou polovinu pole.</li><li>Analogicky, je-li menší než k, můžeme hledat jen v pravé polovině.</li></ul><p>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.</p><p>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á <i>logaritmickou časovou složitost</i>, píšeme O(log n). (Pokud není řečeno jinak, znamená pro nás v informatice značka log <i>dvojkový logaritmus</i>, 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.)</p><p>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.</p><p>FIXME code</p><h4>Další aplikace</h4><p>Další typickou aplikací postupu rozděl a panuj je například třídění posloupnosti pomocí <i>Mergesortu</i>. 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.</p><p>Více se o metodě Rozděl a panuj můžete dozvědět ve stejnojmenné <a href=\"https://ksp.mff.cuni.cz/viz/kucharky/rozdel-a-panuj\">kuchařce</a>.</p>",
"htmlContent":"<h3>Rozděl a panuj</h3><p>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.</p><h4>Binární vyhledávání v poli</h4><p>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é.</p><p>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:</p><ul><li>Pokud je roven k, jsme hotovi.</li><li>Je-li větší než k, víme, že se k musí nacházet nalevo od něj. Můžeme tedy hledat znovu, ale tentokrát se omezit jen na levou polovinu pole.</li><li>Analogicky, je-li menší než k, můžeme hledat jen v pravé polovině.</li></ul><p>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.</p><p>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á <i>logaritmickou časovou složitost</i>, píšeme O(log n). (Pokud není řečeno jinak, znamená pro nás v informatice značka log <i>dvojkový logaritmus</i>, 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.)</p><p>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.</p><p>FIXME code</p><h4>Další aplikace</h4><p>Další typickou aplikací postupu rozděl a panuj je například třídění posloupnosti pomocí <i>Mergesortu</i>. 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.</p><p>Více se o metodě Rozděl a panuj můžete dozvědět ve stejnojmenné <a href=\"https://ksp.mff.cuni.cz/viz/kucharky/rozdel-a-panuj\">kuchařce</a>.</p>",
"position":[
"position":[
-841.6388244628906,
-1055.2265319824219,
755.4090232849121
787.3630638122559
]
]
},
},
{
{
@ -2258,8 +2261,8 @@
"title":"Dvourozměrné prefixové součty",
"title":"Dvourozměrné prefixové součty",
"htmlContent":"<h4>Dvourozměrné prefixové součty</h4><p>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].</p><p>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?</p><p>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:</p><figure class=\"image\"><img src=\"https://ksp.mff.cuni.cz/kucharky/zakladni-algoritmy/zakladni_algoritmy-6.png\" alt=\"Dvourozměrné prefixové součty\"></figure><p>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.</p><p>Celý vzorec tedy vypadá takto:</p><p>soucet = P[X,Y] - P[X,y] - P[x,Y] + P[x,y];</p><p>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é <i>princip inkluze a exkluze</i> a najde použití nejen u vícerozměrných prefixových součtů.</p>",
"htmlContent":"<h4>Dvourozměrné prefixové součty</h4><p>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].</p><p>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?</p><p>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:</p><figure class=\"image\"><img src=\"https://ksp.mff.cuni.cz/kucharky/zakladni-algoritmy/zakladni_algoritmy-6.png\" alt=\"Dvourozměrné prefixové součty\"></figure><p>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.</p><p>Celý vzorec tedy vypadá takto:</p><p>soucet = P[X,Y] - P[X,y] - P[x,Y] + P[x,y];</p><p>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é <i>princip inkluze a exkluze</i> a najde použití nejen u vícerozměrných prefixových součtů.</p>",