úlohy na DP a prefixáky
This commit is contained in:
parent
1237d32514
commit
fe7d72429a
1 changed files with 51 additions and 38 deletions
89
tasks.json
89
tasks.json
|
@ -122,7 +122,7 @@
|
|||
"title": "Životně důležitá úloha",
|
||||
"position": [
|
||||
-90.7659363746643,
|
||||
879.8850021362305
|
||||
880.786247253418
|
||||
],
|
||||
"taskReference": "26-Z2-4",
|
||||
"points": 12
|
||||
|
@ -825,11 +825,12 @@
|
|||
"kucharka-zakladni-dynamicke-programovani"
|
||||
],
|
||||
"position": [
|
||||
153.05905151367188,
|
||||
506.2679748535156
|
||||
-273.39971923828125,
|
||||
1197.8036499023438
|
||||
],
|
||||
"title": "Čtyřková",
|
||||
"points": 12
|
||||
"points": 12,
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "open-data",
|
||||
|
@ -1144,7 +1145,7 @@
|
|||
"taskReference": "30-1-4",
|
||||
"requires": [],
|
||||
"position": [
|
||||
2425.829833984375,
|
||||
2427.345458984375,
|
||||
1017.5477600097656
|
||||
],
|
||||
"title": "Cesta v bunkru",
|
||||
|
@ -1169,10 +1170,12 @@
|
|||
"type": "open-data",
|
||||
"id": "30-3-1",
|
||||
"taskReference": "30-3-1",
|
||||
"requires": [],
|
||||
"requires": [
|
||||
"30-Z4-1"
|
||||
],
|
||||
"position": [
|
||||
2260.394287109375,
|
||||
885.5089416503906
|
||||
-513.2063903808594,
|
||||
1192.0383605957031
|
||||
],
|
||||
"title": "Vlnění",
|
||||
"hidden": true,
|
||||
|
@ -1182,13 +1185,15 @@
|
|||
"type": "open-data",
|
||||
"id": "30-4-5",
|
||||
"taskReference": "30-4-5",
|
||||
"requires": [],
|
||||
"requires": [
|
||||
"kucharka-zakladni-dynamicke-programovani"
|
||||
],
|
||||
"position": [
|
||||
2434.596923828125,
|
||||
816.7156677246094
|
||||
-376.9443664550781,
|
||||
1235.2302551269531
|
||||
],
|
||||
"title": "Frňákovník",
|
||||
"hidden": true,
|
||||
"hidden": false,
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
|
@ -1310,12 +1315,14 @@
|
|||
"taskReference": "30-Z2-4",
|
||||
"title": "Příliš bílý displej",
|
||||
"comment": " Práce s 2d polem",
|
||||
"requires": [],
|
||||
"position": [
|
||||
-1553.5021209716797,
|
||||
-1031.9203643798828
|
||||
"requires": [
|
||||
"kucharka-zakladni-prefixove-soucty-2d"
|
||||
],
|
||||
"hidden": true,
|
||||
"position": [
|
||||
-710.1918792724609,
|
||||
1333.6874084472656
|
||||
],
|
||||
"hidden": false,
|
||||
"points": 12
|
||||
},
|
||||
{
|
||||
|
@ -1381,12 +1388,14 @@
|
|||
"taskReference": "30-Z4-1",
|
||||
"title": "Statistika sprintů",
|
||||
"comment": " Prefixové součty",
|
||||
"requires": [],
|
||||
"position": [
|
||||
-1586.7162628173828,
|
||||
-1087.0154418945312
|
||||
"requires": [
|
||||
"kucharka-zakladni-prefixove-soucty"
|
||||
],
|
||||
"hidden": true,
|
||||
"position": [
|
||||
-623.6291046142578,
|
||||
1118.8409271240234
|
||||
],
|
||||
"hidden": false,
|
||||
"points": 8
|
||||
},
|
||||
{
|
||||
|
@ -1435,13 +1444,15 @@
|
|||
"type": "open-data",
|
||||
"id": "31-1-1",
|
||||
"taskReference": "31-1-1",
|
||||
"requires": [],
|
||||
"requires": [
|
||||
"28-Z4-4"
|
||||
],
|
||||
"position": [
|
||||
2454.366792678833,
|
||||
946.1978244781494
|
||||
-280.69116020202637,
|
||||
1289.7996921539307
|
||||
],
|
||||
"title": "Karkulčin byznys",
|
||||
"hidden": true,
|
||||
"hidden": false,
|
||||
"points": 12
|
||||
},
|
||||
{
|
||||
|
@ -2138,12 +2149,14 @@
|
|||
"id": "kucharka-zakladni-dynamicke-programovani",
|
||||
"type": "text",
|
||||
"comment": "...",
|
||||
"requires": [],
|
||||
"requires": [
|
||||
"kucharka-zakladni-prefixove-soucty"
|
||||
],
|
||||
"title": "Dynamické programování",
|
||||
"htmlContent": "<h3>Předpočítané mezivýsledky</h3><p>Motivací k této kapitole je následující motto: „Proč počítat něco vícekrát, když nám to stačí spočítat jednou a zapamatovat si to?“.</p><p>Velmi často se totiž setkáváme s tím, že něco počítáme stále dokola. Jako příklad si můžeme připomenout naši rekurzivní implementaci počítání Fibonacciho čísel zmíněnou výše.</p><p>Když se podíváme na výpočet čísla fib(5), vidíme, že pro něj voláme fib(4) a fib(3), fib(4) volá fib(3) a fib(2), fib(3) volá fib(2) a fib(1) a tak dále. Všimli jste si, kolikrát se nám tyhle výpočty opakují? Některá Fibonacciho čísla spočteme totiž zbytečně mnohokrát.</p><figure class=\"image\"><img src=\"https://ksp.mff.cuni.cz/kucharky/zakladni-algoritmy/zakladni_algoritmy-5.png\" alt=\"Strom výpočtu Fibonacciho čísla\"></figure><p>Kdybychom si je namísto opakovaného počítání někde pamatovali, mohli bychom pak odpověď na dotaz na již vypočtené číslo vytáhnout jako králíka z klobouku v konstantním čase. Zavedením jednoho globálního pole, ve kterém si tyto hodnoty pro jednotlivá n budeme pamatovat, nám sníží časovou složitost z O(2n) na pěkných O(n). Takovému postupu se obecně říká <i>dynamické programování</i>.</p><h4>Dynamické programování</h4><figure class=\"image\"><img src=\"https://ksp.mff.cuni.cz/img/hippo_dynamit.png\" alt=\"Dynamitské programování\"></figure><p>Nejprve uveďme na pravou váhu výraz „dynamické“ v názvu. Nevystihuje tak úplně podstatu této techniky a jeho historické pozadí je celkem složité, avšak dnes je tento název již tak zažitý, že se už pravděpodobně nezmění.</p><p>Slovo „dynamické“ částečně odkazuje na to, že se dynamicky (za běhu programu) postupně staví řešení jednodušších problémů, která jsou následně použita pro řešení složitějších. Jeho hlavní podstatou je tedy ukládání a opětovné použití již jednou vypočtených údajů.</p><p>Hodí se na úlohy, které se dají dělit na podúlohy, které jsou si podobné a mohou se opakovat. Výsledky takovýchto podúloh si poté ukládáme a při dotazu na stejnou podúlohu vrátíme jen uložený výsledek a výpočet již neprovádíme.</p><p>Pro další prohloubení znalostí můžete na našem webu nahlédnout do další kuchařky, tentokrát nesoucí (překvapivě) název <a href=\"https://ksp.mff.cuni.cz/viz/kucharky/dynamicke-programovani\">Dynamické programování</a>.</p>",
|
||||
"position": [
|
||||
105.5970230102539,
|
||||
425.50379943847656
|
||||
-332.6829147338867,
|
||||
1135.6282806396484
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2212,8 +2225,8 @@
|
|||
"title": "Pole",
|
||||
"htmlContent": "<p>První datovou strukturou, kterou si představíme a která se na výše nastíněnou situaci náramně hodí, je <i>pole</i>. To představuje spoustu přihrádek (proměnných) naskládaných v paměti za sebou, ke kterým typicky přistupujeme přes jeden společný název pole a jejich pořadové číslo neboli index (jako NazevPole[0], NazevPole[1], …). (Pozor, ve světě počítačů se velmi často indexuje od nuly, tedy první prvek má v tomto případě index 0.)</p><p>Ve většině základních jazyků je pole jen <i>statické</i>, tedy v okamžiku jeho vytváření musíme počítači říct, jak ho chceme velké. Některé vyšší jazyky ale nabízejí i pole, které se dynamicky zvětšuje, takovou konstrukci si ukážeme ve druhé části kuchařky.</p><p>Abychom nebyli omezeni jen jedním rozměrem, můžeme si klidně vyrobit pole dvourozměrné (případně obecně n-rozměrné). Dvourozměrné pole je vlastně tabulka hodnot, nazýváme ji také někdy <i>matice</i>, a může se nám hodit například při reprezentaci různých map (plán bludiště) nebo, jak uvidíme níže, pro reprezentaci dalších datových struktur.</p><p>U pole již má smysl přemýšlet, jak dlouho bude která operace trvat. Díky tomu, že jsou jednotlivé prvky v poli naskládané pevně za sebou, je snadné spočítat umístění konkrétní přihrádky. Proto když se počítače zeptáme na obsah přihrády pole[42], vrátí nám hodnotu ihned.</p><figure class=\"image\"><img src=\"https://ksp.mff.cuni.cz/img/hippo_array.png\" alt=\"Pole\"></figure><p>Tomu budeme říkat <i>operace v konstantním čase</i> a budeme značit, že trvá čas O(1). Efektivitu programu totiž nepočítáme v sekundách (protože každý z nás má asi jinak rychlý počítač), ale v počtu základních operací, které musí program řádově vykonat. Více o časové složitosti si můžete přečíst v <a href=\"https://ksp.mff.cuni.cz/viz/kucharky/slozitost\">kuchařce o složitosti</a>, nejdříve však doporučujeme dočíst tuto kuchařku.</p><p>Přidání nového prvku na konec pole také zvládneme v konstantním čase. Problém je přidání nového prvku někam doprostřed (což se nám typicky stane, pokud budeme chtít udržovat hodnoty v poli seřazené a zároveň do něj vkládat nové). V takovém případě se totiž všechny prvky za vkládaným musí posunout o jednu pozici dál, aby se vkládaný prvek vešel na své místo. Taková operace tedy může pro pole délky N (čili pole obsahující N prvků) trvat řádově až N kroků, což zapisujeme jako O(N) a říkáme, že je to vzhledem k N <i>lineární časová složitost</i>.</p><p>To je značná nevýhoda oproti struktuře, kterou si ukážeme za chvíli. Určitě ale pole nezavrhujme. Je to základní datová struktura, která nalezne použití ve spoustě programů, a jak si ve druhé části kuchařky ukážeme, můžeme ho použít třeba k rychlému hledání hodnoty metodou <i>binárního vyhledávání</i>. Nyní ale již slibovaná další datová struktura.</p>",
|
||||
"position": [
|
||||
-386.3838195800781,
|
||||
714.8706398010254
|
||||
-396.99383544921875,
|
||||
655.7576637268066
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2235,13 +2248,13 @@
|
|||
"type": "text",
|
||||
"comment": "https://ksp.mff.cuni.cz/kucharky/zakladni-algoritmy/",
|
||||
"requires": [
|
||||
"kucharka-zakladni-prefixove-soucty"
|
||||
"30-Z4-1"
|
||||
],
|
||||
"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>",
|
||||
"position": [
|
||||
-714.1817283630371,
|
||||
1252.7593383789062
|
||||
-710.7839622497559,
|
||||
1225.3379516601562
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2415,15 +2428,15 @@
|
|||
{
|
||||
"id": "placeholder-kurz-programovani",
|
||||
"type": "text",
|
||||
"comment": "...",
|
||||
"comment": "",
|
||||
"requires": [
|
||||
"programovani"
|
||||
],
|
||||
"title": "Placeholder pro základní kurz programování",
|
||||
"htmlContent": "<p>Tady by měl začítat kurz programování. Chceme ze stávajícího kurzu vybrat úlohy a dát je sem. Postupně by asi také bylo fajn to celé rozvinou do větších detailů.</p>",
|
||||
"title": "Základní kurz programování",
|
||||
"htmlContent": "<p>Tady by měl začítat kurz programování. Chceme ze stávajícího kurzu vybrat úlohy a dát je sem. Postupně by asi také bylo fajn to celé rozvinou do větších detailů.</p><p> </p><p>Zatím je základní kurz na https://ksp.mff.cuni.cz/kurzy/zkp/1-uvod/</p>",
|
||||
"position": [
|
||||
271.81773376464844,
|
||||
322.83670806884766
|
||||
324.0678482055664
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
Reference in a new issue