(Rozděl a panuj. Dynamické programování. Hladové strategie. Backtracking. Meze použitelnosti i jednotlivých technik. Příklady algoritmů postavených na jednotlivých technikách.)
Túto techniku je možné ľahko popísať týmito krokmi.
Problém 1, Maximálny a minimálny prvok
Algoritmus 1, Naivný algoritmus riešiaci problém maximálneho prvku
Max(S) 1 max ← S[1] 2 for i = 2 to n do 3 if S[i] > max then max ← S[i] fi 4 od
Procedúra Max nájde najväčší prvok, podobne sa nájde medzi ostatnými prvkami najmenší prvok. Časová zložitosť tohto algoritmu je zrejme (n - 1), pokud k tomu přidáme složitost hledání minimálního prvku (n-2) (hľadáme už len medzi n-1 prvkami) máme 2n-3.
Algoritmus 2, Rozdeľ a panuj algoritmus riešiaci problém maximálneho a minimálneho prvku
function Maxmin(x, y) **predpoklad x < y 1 if y = x + 1 then return (max(S[x], S[y]),min(S[x], S[y])) fi 2 if y = x + 2 3 then použitím 3 porovnaní utrieď S[x], S[x + 1], S[y] 4 return (max, min) 5 fi 6 if y > x + 2 then 7 (max1, min1) ← Maxmin(x, ⌊(x + y)/2⌋) 8 (max2, min2) ← Maxmin(⌊(x + y)/2⌋ + 1, y) 9 return (max(max1, max2), min(min1, min2)) 10 fi
Ľahko dokážeme, že tento algoritmus je korektný. Jeho časová zložitosť je:
Indukciou sa dá ľahko dokázať, že
Časovú zložitosť máme často určenú rekurzívne. Vtedy sa jej dôkaz často oplatí použiť tzv. Master Theorem.
Def. 1, Master Theorem
Inými typickými príkladmi použitia Rozdeľ a panuj sú algoritmy mergesort, … .
Táto technika je vhodná pre riešenie optimalizačných problémov, u ktorých dochádza k prekrývaniu podproblémov.
Problém 2, Najväčšia spoločná podpostupnosť
Označenie: pre postupnosť X = definujeme jej i-ty prefix (pre i=0,…,n) ako Nech X = a Y = sú postupnosti symbolov a nech Z = je ich NSP.
Definujme c[i,j] ako dĺžku NSP postupností Xi a Yj. Platí
Poradie výpočtu:
c[1,1],…,c[1,m]
c[2,1],…,c[2,m]
.
.
.
c[n,1],…,c[n,m]
Algoritmus 2, Výpočet optimálneho riešenia
NSP(X, Y) 1 for i = 1 to m do c[i, 0] ← 0 od 2 for j = 0 to n do c[0, j] ← 0 od 3 for i = 1 to m do 4 for j = 1 to n do 5 if Xi = Yj then 6 c[i, j] ← c[i − 1, j − 1] + 1 7 b[i, j] ← ♣ 8 else if c[i − 1, j] ≥ c[i, j − 1] then 9 c[i, j] ← c[i − 1, j] 10 b[i, j] ← ♠ 11 else 12 c[i, j] ← c[i, j − 1] 13 b[i, j] ← ♥ 14 fi fi od od 15 return c, b
Algoritmus 2, Zostavenie optimálneho riešenia
Print NSP(b, X, i, j) 1 if i = 0 ∨ j = 0 then return fi 2 if b[i, j] = ♣ then 3 Print NSP(b, X, i − 1, j − 1) 4 print xi 5 else if b[i, j] = ♠ then 6 Print NSP(b, X, i − 1, j) 7 else 8 Print NSP(b, X, i, j − 1) 9 fi fi
Ďalšími príkladmi dynamického programovanie sú algoritmy: Floydov algoritmus, Warshallov algoritmus, Konštrukcia vyváženého vyhľadávacieho stromu, … .
Táto technika však nie je použiteľná pre všetky optimalizačné problémy.
Problém 3, Problém pásky
Problém má optimálnu štruktúru, pretože ak ako prvý uložíme na pásku súbor i, ostané súbory musíme usporiadať optimálne.
Hladový algoritmus: KLO = vyber spomedzi ešte neuložených súbor najkratší a ulož ho na pásku (t.j. ulož na pásku súbory od najkratsieho po najdlhší)
Dôkaz, že je takýto algoritmus naozaj korektný je možné nájsť v slajdoch k predmetnu Návrh algoritmů II.
Medzi iné hladové algoritmy patrí Dijsktrov algoritmus, Primov a Kruskallov algoritmus pre najlacnejšie kostry, Huffmanove kódy, …
Technika prehľadávania priestoru potencionálnych riešení založená na princípe Rozdeľ a panuj.
Problém 4, Problém tyčí
Pozn. Tento problém je riešiteľný dynamickým programovaním v O(nD).
Algoritmus 3, Algoritmus riešiaci problém n-tyčí
Tyč(m, l) 1 if m = 0 then 2 if l = 0 then print A fi 3 else 4 A[m] ← 0 5 Tyč(m − 1, l) 6 7 if dm ≤ l then 8 A[m] ← 1 9 Tyč(m − 1, l − dm) 10 fi 11 fi
Pri používaní backtrackingu budeme často potrebovať preskúšať všetky permutácie. Tu je algoritmus na ich zistenie.
Algoritmus 4, Algoritmus pre získanie všetkých permutácií
procedure Permutácie(m) 1 if m = 1 then kontrola vlastností else Permutácie(m − 1) 2 for i = m − 1 downto 1 do 3 vymeň A[m] a A[i] 4 Permutácie(m − 1) 5 vymeň A[m] a A[i] 6 od fi
Ľuboš Pecho, 172463, tomorrow@mail.muni.cz, 18.6.2008