====== 0 - Příprava na složitost ======
==== Řešené úlohy ====
=== Uvažování nad kódem ===
**Řešená úloha 1:** Který fragment programu z následujících dvou proběhne rychleji? (Předpokládáme, že oba běží v identickém SW/HW prostředí.)
int n = 100;
int sum = 0;
for (i = 0; i < n; i++)
for (j = 0; j < i; j++)
sum += i+j;
int n = 75;
int sum = 0;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
sum += i+j;
++++ Řešení (rozbalit)|
Ten nalevo, protože $\sum_{i=0}^{99} i = 100\frac{99}{2} = 4950 < 5625 = 75^2$
Vyplatí se znát vzorec pro součet $q$ členů aritmetické posloupnosti: $\sum_{i = 1}^{q} a_i = q \frac{a_1 + a_q}{2} $. [[https://en.wikipedia.org/wiki/Arithmetic_progression|Vizuální důkaz.]]
[[https://www.onlinegdb.com/B10Gs6y2W | Simulace běhu]]
++++
-----
**Řešená úloha 2:** Do následujícího kódu doplňte chybějící konstantu v podmínce tak, aby byla procedura ''xyz()'' volána právě **2000 krát**.
i = 50;
do {
for (j = 0; j < 70; j++) {
if (j > ___) xyz();
}
i++;
} while (i < 150);
Můžete zkusit svůj tip [[https://www.onlinegdb.com/B1WXapy2W | zde]].
++++ Řešení (rozbalit)|
Vnější cyklus vykoná $100$ iterací. Protože $2000 / 100 = 20$, musí podmínka platit vždy ve $20$ iteracích vnitřního cyklu. Z toho $70 - 20 = 50$ musí být první $j$, pro které bude podmínka platit, tj. **chybějící konstanta je** $49$.
++++
----
=== Výpočetní úlohy ===
**Řešená úloha 3:** Ke zpracování $k$-tého řádku matice velikosti $n \times n$ je zapotřebí $2k$ operací. Kolik je potřeba operací ke zpracování celé matice?
a) $2n^2$ \\
b) $n^2 / 2$ \\
c) $n(n+1) / 2$ \\
d) $n(n-1)$ \\
e) $n(n+1)$
++++ Řešení (rozbalit)|
Správně je **e)**: Součet pro $n$ řádků (aritmetická posloupnost): $\sum_{k=1}^n 2k = n\frac{2 + 2n}{2} = n(n+1)$.
++++
----
**Řešená úloha 4:** Úloha, jejíž doba řešení je $Cn^2$, kde $n$ je rozsah vstupních dat, se řeší na
počítači pro $n=5000$. Je zakoupen nový počítač, který je cca $2.5\times$
rychlejší. Jak lze zvětšit rozsah vstupních dat, aby byla úloha vyřešena na
novém počítači ve stejném čase?
++++ Řešení (rozbalit)|
Sestavíme rovnici mezi $2.5$-násobkem času běhu na starém počítači a časem běhu na novém PC
$C n_{new}^2 &= 2.5 C n_{old}^2$.
Z toho vypočteme $n_{new} = \sqrt{2.5 \cdot 5000^2} \approx 7905.694$
Tj. za stejný čas lze úloha vyřešit na $2.5\times$ rychlejším počítači pro $n_{new}=7905$ (po zaokrouhlení dolů). Neboli, data lze zvětšit $\sqrt{2.5} \approx 1.58 \times$.
++++
----
=== Konstrukční úlohy ===
**Řešená úloha 5:** Pole obsahuje kladné a nulové prvky. Popište, jak zorganizujete
jeden průchod polem, po jehož doběhnutí budou všechny
nenulové prvky shromážděny na začátku pole a jejich pořadí
zůstane zachováno.
Např: z $(3, 2, 0, 6, 0, 0, 9, 0, 2, 0)$ vytvořit $(3, 2, 6, 9, 2, 0, 0, 0, 0, 0)$
++++ Řešení (rozbalit)|
Procházíme seznamem zleva, jakmile najdeme 0, zapamatujeme si pozici a pokračujeme ukazatelem dál, dokud nenajdeme nenulové číslo. To pak prohodíme za 0 na zapamatované pozici. Další pozice s nulou je jistě o jedno pole napravo od té předchozí. Ukazatelem pokračujeme dál, prohazujeme takto každé nenulové číslo které najdeme. Algorimtus končí, jakmile se dostaneme ukazatelem na konec seznamu.
[[https://trinket.io/python/aab6486ab2 | alternativní implementace v Pythonu]]
++++
----
**Řešená úloha 6:** Seznam obsahuje $N+1$ celých čísel, každé leží v intervalu $[1,N]$,
čísla nejsou v seznamu nijak uspořádána. Víme, že v seznamu se
vyskytuje jedno číslo dvakrát, ostatní jen jednou. Určete
duplikované číslo. Musí vám stačit jeden průchod seznamem a
konstantně velká přidaná paměť.
++++ Řešení (rozbalit)|
Využijeme opět součtu posloupnosti, jelikož víme, že seznam obsahuje každé z nich alespoň jednou. Pokud označíme $d$ hodnotu čísla které hledáme (je v seznamu dvakrát), pak součet všech čísel v seznamu je roven $S = d + \sum_{i=1}^N i$. Stačí tedy sečíst všechna čísla v seznamu a vypočítat $d = S - N\frac{N+1}{2}$.
[[https://trinket.io/python3/d306655e20 | implementace v Pythonu]]
++++
----
==== Další úlohy ====
**Úloha 7:** Do následujícího kódu doplňte chybějící konstantu v podmínce tak, aby byla procedura ''xyz()'' volána právě **2100 krát**.
for (i = 0; i < 70; i++) {
j = 0;
do {
if (j > ___) {
xyz();
}
j++;
} while (j < 90);
}
Můžete zkusit svůj tip [[https://www.onlinegdb.com/Bysg36kh- | zde]].
----
**Úloha 8:**
Do následujícího kódu doplňte chybějící výraz v podmínce tak, aby
byla procedura ''uvw()'' volána právě **49 krát**.
for (i = 0; i < 7; i++) {
j = i;
while (j < ___) {
uvw();
j++;
}
}
Můžete zkusit svůj tip [[https://www.onlinegdb.com/ByEGxRx3W | zde]].
----
**Úloha 9:**
Do následujícího kódu doplňte chybějící konstantu v podmínce tak,
aby byla procedura ''uvw()'' volána právě **85 krát**.
i = 0;
while (i < 10) {
for (j = i; j < ___; j++) {
uvw();
}
i++;
}
Můžete zkusit svůj tip [[https://www.onlinegdb.com/By56--Z3Z | zde]].
----
**Úloha 10:**
Řešíme úlohu na počítači pro velikost vstupu $n=5000$. Je zakoupen nový počítač,
který je cca $2.5\times$ rychlejší. O kolik lze zvětšit rozsah vstupních dat, aby
byla úloha vyřešena na novém počítači ve stejném čase?
Řešte pro různé doby řešení úlohy:
a) $C n^3$ \\
b) $C n^{0.5}$ \\
c) $C n \log_2 n$
----
**Úloha 11:**
{{page>courses:b4b33alg:internal:tutorial-notes:00#11&noheader&nofooter}}
Stroj provádí $10^9$ operací za sekundu. Pro výpočet je k dispozici 1
hodina. Určete, jaká může být maximální hodnota $n_{\max}$, která určuje
velikost vstupních dat, v případě že počet nezbytných opreací pro
zpracování dat o velikosti $n$ je $n^{3/2}$.
A co v případě že zpracování vyžaduje \\
a) $N^{5/4}$ operací \\
b) $N \cdot \log_2(N) \cdot \log_2 (\log_2 N)$ operací \\
c) $N^2 \cdot \log_2 N$ operací \\
----
**Úloha 12:**
{{page>courses:b4b33alg:internal:tutorial-notes:00#12&noheader&nofooter}}
Metoda A potřebuje k vyřešení úlohy $n^2 + 17$ operací, Metoda B
potřebuje $2n + 80$ operací, přičemž celé číslo $n$ popisuje rozsah
vstupních dat. Pro jaká $n$ je výhodnější použít metodu A?
[[https://www.wolframalpha.com/input/?i=n%5E2%2B17+%3C+2n+%2B+80 | výpočet]]
----
**Úloha 13:**
{{page>courses:b4b33alg:internal:tutorial-notes:00#13&noheader&nofooter}}
Každý ze dvou seznamů čísel je uspořádán v neklesajícím pořadí.
Popište, jak vytvoříte třetí seznam, který bude obsahovat pouze
taková čísla, která se vyskytují v obou daných seznamech. Musí
vám stačit jeden průchod každým z daných seznamů.
[[https://trinket.io/python/5040d42d6c | implementace v Pythonu]]
----
**Úloha 14:**
Seznam obsahuje kladná čísla, záporná čísla a nuly v nahodilém
pořadí. Najděte takový souvislý podseznam, v němž součet všech
jeho prvků je maximální možný mezi všemi souvislými
podseznamy. Uvažte, zda na to může stačit jeden průchod daným
seznamem.
[[https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/ | implementace]]
----
**Úloha 15:**
{{page>courses:b4b33alg:internal:tutorial-notes:00#15&noheader&nofooter}}
Je dána zafixovaná matice M o rozměru $N \times N$. Máme postupně
odpovídat na množství dotazů stejného formátu:
> Jaký je součet všech hodnot v podmatici, která má levý horní roh na pozici $(i_1, j_1)$ a pravý dolní roh na pozici $(i_2, j_2)$?
Hodnoty $i_1, j_1, i_2, j_2$ budou v každém dotazu obecně jiné.
K dispozici máte paměťový prostor stejně velký jako zabírá M.
Určete, jaké hodnoty si musíte předpočítat, abyste na každý dotaz
odpověděli v co nejkratším čase a nezávisle na velikosti hodnot $i_1, j_1, i_2, j_2$.
[[https://www.geeksforgeeks.org/submatrix-sum-queries/ | implementace]]
----
**Úloha 16:**
V rovině je dána kružnice se středem v počátku a poloměrem $R$.
Popište, jak určíte, kolik celočíselných mřížových bodů leží uvnitř
této kružnice. Neprocházejte všechny mřížové body ve čtvereci o
velikosti $2R\times2R$, využijte pouze mřížové body ležící blízko kružnice.
Napište kompletní kód Vašeho řešení.