1 / 33

Trojúhelník z čísel N řádků, obsahují 1, 2, 3, …, N čísel – zadán na vstupu Příklad pro N =5:

karif
Télécharger la présentation

Trojúhelník z čísel N řádků, obsahují 1, 2, 3, …, N čísel – zadán na vstupu Příklad pro N =5:

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dynamické programováníProgramovací technika pro řešení takových optimalizačních úloh, u nichž platí, že úloha se dá rozložit na menší podúlohy, z jejichž optimálních řešení se skládá optimální řešení celé původní úlohy.Slouží k tvorbě časově efektivních algoritmů, zpravidla za cenu jistého zvýšení paměťových nároků - čas i paměť polynomiální (nahradí backtracking s exponenciální časovou složitostí).Princip:Rozklad úlohy na menší podúlohy stejného charakteru, z jejichž řešení se sestaví řešení původní úlohy – podobné jako u techniky „Rozděl a panuj“.Na rozdíl od techniky „Rozděl a panuj“ nemusejí být podúlohy navzájem nezávislé  širší možnosti použití. Programování - 23

  2. Postup:Na rozdíl od „Rozděl a panuj“ se obvykle nepoužívá rekurzivní rozklad úlohy shora, ale postupuje se naopak zdola od elementárních úloh ke složitějším. Výsledky řešení všech podúloh se přitom ukládají (zpravidla do pole) pro další použití při řešení složitějších podúloh. Tak se postupuje, dokud se nevyřeší celá původní úloha.Lze postupovat také rekurzivním rozkladem shora a do pomocného pole si při tom průběžně ukládat všechny spočítané hodnoty, aby se nepočítaly opakovaně znovu (viz „chytrá rekurze“). Programování - 23

  3. Paměťové nároky:Potřebujeme paměť navíc pro uložení výsledků všech dílčích podúloh – při iteračním postupu zdola dokonce často i těch, které nakonec nebudeme vůbec potřebovat (ale předem nevíme, které dílčí výsledky později potřebovat budeme a které ne, takže si počítáme a ukládáme systematicky všechny). Tyto dodatečné paměťové nároky mohou být velikosti O(N), velmi často bývají O(N2) – tedy dvourozměrné pole. V každém případě jsou polynomiální. Programování - 23

  4. Časová efektivita:Díky ukládání výsledků všech menších podúloh máme zajištěno, že se žádná podúloha nebude počítat opakovaně vícekrát – může se jen vícekrát použít její výsledek uložený již jednou v poli. Proto nemusejí být podúlohy na sobě navzájem nezávislé a přesto je zaručena polynomiální časová složitost výpočtu.Počet provedených operací = počet řešených podúloh (počet prvků pole určeného pro uložení všech dílčích výsledků) x náročnost řešení každé jednotlivé podúlohy (s využitím toho, že už známe výsledky podúloh menších).Příklad: N2 x N = N3  časová složitost O(N3) Programování - 23

  5. PříkladyUž známe: Fibonacciho číslaUrčení N-tého Fibonacciho čísla rekurzivní funkcí – chybně použitý princip „Rozděl a panuj“, vznikající podúlohy byly závislé  exponenciální časová složitostUrčení N-tého Fibonacciho čísla postupným počítáním zdola v cyklu – princip dynamického programování, nic se nepočítá opakovaně vícekrát  lineární časové složitost Programování - 23

  6. Trojúhelník z číselN řádků, obsahují 1, 2, 3, …, N čísel – zadán na vstupuPříklad pro N=5: 73 88 1 02 7 4 44 5 2 6 5 Úkol: nalézt cestu z vrcholu na základnu s maximálním součtem čísel, smí se jít vždy jen šikmo směrem dolů. Řešení: 73 88 1 02 7 4 44 5 2 6 5 Programování - 23

  7. Postup řešení1. Neefektivní:- uložit všechna čísla do pole  paměť O(N2)- backtrackingem postupně zkoušet všechny cesty  čas O(2N)2. Dynamické programování:- načíst a uložit vždy jen jeden řádek čísel, spočítat a uložit maximální součet čísel na cestě vedoucí do každého z nich paměť O(N)[některé z těchto údajů se ve výsledku neuplatní, ale ještě nevíme které, tak počítáme a ukládáme všechny]- další řádek spočítat vždy z předchozího, každé číslo má jen dva možné předchůdce a součty maximálních cest do nich vedoucích máme uloženy- výsledkem je maximální spočítaná hodnota v posledním řádku- počítáme tedy řádově N2 čísel, každé určíme v konstantním čase  časová složitost O(N2) Programování - 23

  8. Dokonalé naplnění vozidlaMáme N předmětů známých hmotností. Lze z nich vybrat skupinu předmětů se součtem hmotností rovným přesně dané hodnotě C ?Tzn. lze na vozidlo nosnosti C naložit některé z předmětů tak, aby bylo auto plně vytíženo?Poznámka: Hmotnosti všech předmětů i výsledná hmotnost C jsou celá čísla nepřevyšující předem známou hodnotu Max (lze jimi tedy indexovat, jinak by to byla mnohem těžší úloha).Postup řešení:Sledujeme maximální možné zaplnění fiktivních „aut“ o nosnostech 1,…,C pomocí prvních i předmětů. Bereme jeden předmět za druhým (v libovolném pořadí) a zaplnění každého z aut vždy zkoušíme zlepšit. Po zpracování všech N předmětů známe optimální zaplnění auta C, což nám dává požadovaný výsledek. Programování - 23

  9. Otázka:Proč jsme uvažovali všechna ta menší auta, když ta vůbec neexistují a nikdo se nás na ně neptal?Odpověď: To je právě dynamické programování – s jejich pomocí snáze (a hlavně efektivněji) dokážeme přepočítávat optimální zaplnění cílového auta, když postupně přibývají předměty. Programování - 23

  10. Zk(i) = maximální zaplnění auta nosnosti k pomocí prvních i předmětůnechť i-tý předmět má hmotnost AZk(i) = Zk(i-1) … pokud A> k (i-tý předmět se na k-té auto nevejde) Zk(i) = max (Zk(i-1), A + Zk-A(i-1)) … pokud A<= k  i-tý předmět i-tý předmět nepoužijeme použijeme Programování - 23

  11. Složitost:Paměť – stačí jedno pole velikost C, v něm se přepočítávají hodnoty Zk, a to odzadu (!!!) – k výpočtu Zk(i) potřebujeme znát hodnoty Zm(i-1) pro m<=k.Čas – postupně N-krát přepočítat maximálně C hodnot v poli.Výsledek:ZC(N) = maximální zaplnění kapacity C pomocí všech N předmětů.Pokud je tato hodnota rovna C, existuje dokonalé zaplnění. Programování - 23

  12. Výběr předmětů:Existuje-li dokonalé zaplnění, které předměty máme vybrat?1. Přímočarý, ale paměťově náročný postup:U každého „auta“ si stále pamatujeme seznam čísel předmětů, pomocí nichž jsme docílili zatím nejlepšího zaplnění. Při každé změně hodnoty Zkna A + Zk-A(i-1) (použili jsme i-tý předmět) zkopírujeme seznam naložených předmětů od (k-A)-tého auta a přidáme k němu i.Nakonec máme u výsledného auta i seznam naložených předmětů.2. Postup s lineární pamětí: Druhé pole P velikosti C, do něhož ukládáme pořadová čísla předmětů.Pk = číslo předmětu, který jsme naposledy naložili do auta nosnosti k při postupném výpočtu hodnot Zk(i)- mění se vždy při změně hodnoty Zk: když Zk(i)> Zk(i-1), pak Pk := iZ hodnot uložených v poli P se odzadu od PC zpětně zrekonstruuje způsob zaplnění C-tého auta. Programování - 23

  13. Floyd-Warshallův algoritmusMáme ohodnocený graf bez záporných cyklů (mohou v něm být záporně ohodnocené hrany). A = ( ai, j ) – matice vzdáleností velikosti N x N ai, j = délka hrany (i, j) pro i, j = 1, …, NÚkol: nalézt nejkratší vzdálenosti mezi všemi dvojicemi vrcholůPostup řešení1. Postupně z každého z N vrcholů grafu spustit Dijkstrův algoritmus- časová složitost N x O(N2) = O(N3)- lze použít jen v případě nezáporného ohodnocení hran2. Floyd-Warshallův algoritmus (Floydův algoritmus)- pracuje na principu dynamického programování- paměťová složitost O(N2), časová složitost O(N3) Programování - 23

  14. Zavedeme matici U = ( ui, j ), jejíž hodnoty budeme postupně v N iteracích přepočítávat (číslo iterace uvádíme v horním indexu):ui, j (m)= délka nejkratší cesty z vrcholu i do vrcholu j vedoucí pouze přes vrcholy z množiny {1, …, m}Postup:ui, j (0)= ai, j - přímo vstupní hodnoty (triviální)ui, j (m)- počítáme postupně pro m = 1, …, Nui, j (N) - požadovaný výsledek (triviální)Zbývá ukázat, jak spočítáme hodnoty ui, j (m+1), když už známe ui, j (m)pro všechny dvojice i, j :ui, j (m+1) = min ( ui, j (m) , ui, m+1 (m) + um+1, j (m) )  vrchol m+1 nepoužijeme vrchol m+1 použijeme (právě 1 x) Programování - 23

  15. Efektivita algoritmu:Časová složitost O(N3) – všechny prvky matice U velikosti N x N musíme N-krát přepočítat, každou tuto hodnotu spočítáme v konstantním čase. Paměťová složitost O(N2) - při realizaci přesně podle definice potřebujeme dvě verze matice U, abychom si nepřepisovali hodnoty, které ještě budeme potřebovat- ve skutečnosti přepisování nevadí a stačí provádět výpočet v jedné matici (místo „správné“ hodnoty občas při výpočtu použijeme hodnotu dokonce už „lepší“) Programování - 23

  16. Implementace:for i:=1 to N dofor j:=1 to N doif existuje_hrana(i,j) then U[i,j]:=delka_hrany(i,j)else U[i,j]:=NEKONECNO;for m:=1 to N dofor i:=1 to N dofor j:=1 to N dobegin x:=U[i,m]+U[m,j];if x < U[i,j] then U[i,j]:=xend; Programování - 23

  17. Určení cesty:Co když nám nestačí délky nejkratších cest, ale chceme také vědět, kudy nejkratší cesta vede?Zavedeme druhou matici P = ( pi, j ) velikosti N x N, jejíž prvky budeme přepočítávat zároveň s maticí U:pi, j = nejvyšší číslo vrcholu ležícího na dosud nejkratší nalezené cestě z vrcholu i do vrcholu j provšechna i, j = 1, …, N Programování - 23

  18. for i:=1 to N dofor j:=1 to N doif existuje_hrana(i,j) then U[i,j]:=delka_hrany(i,j)else U[i,j]:=NEKONECNO;for m:=1 to N dofor i:=1 to N dofor j:=1 to N dobegin x:=U[i,m]+U[m,j];if x < U[i,j] thenbeginU[i,j]:=x; P[i,j]:=mendend; Programování - 23

  19. Po skončení výpočtu matic U, P dokážeme z obsahu matice P určit, kudy vede nejkratší cesta mezi libovolnou dvojicí vrcholů i, j :- pokud pi, j = 0, nepoužili jsme při hledání nejkratší cesty z i do j žádný jiný vrchol grafu a nejkratší cestou je tedy přímá hrana mezi těmito dvěma vrcholy- pokud pi, j  0, získáme seznam vrcholů tvořících nejkratší cestu z vrcholu i do vrcholu j voláním následující proceduryprocedure Cesta(i,j: word);var m: word;begin m:=P[i,j];if m <> 0 thenbegin Cesta(i,m); write(m); Cesta(m,j) endend; Programování - 23

  20. Součin maticPočítáme součin matic A1 . A2 . … . ANÚkol: vhodným uzávorkováním minimalizovat počet vykonaných elementárních násobení čísel (máme tedy nalézt ono nejlepší uzávorkování, nikoli spočítat součin matic).Pozorování:nechť matice B má rozměry P x Qnechť matice C má rozměry Q x R součin matic B.C má rozměry P x R a k jeho výpočtu je zapotřebí vykonat P.Q.R násobení číselNechť v naší úloze matice Ai má rozměry Pi-1 x Pi pro i = 1, …, NVstupní data pro úlohu: N, P0, P1, …, PN Programování - 23

  21. Příklad:N=3, zadané rozměry matic 2 5 2 3násobíme tedy matice A1 . A2 . A3 rozměrů 2 x 5 5 x 2 2 x 3existují dvě možná uzávorkování ( A1 . A2 ) . A3rozměry 2 x 2 2 x 3počet násobení 20 12 celkem 32 A1 . ( A2 . A3 )rozměry 2 x 5 5 x 3počet násobení 30 30 celkem 60 Programování - 23

  22. Řešení backtrackingem- systematické zkoumání všech možných uzávorkování daného součinu matic  exponenciální časová složitost.Rekurzivní funkce PocetNasobeni (K, L) určuje minimální počet násobení čísel potřebný k určení součinu matic AK . AK+1 . … . AL .Funkce vyzkouší všechny možnosti, které z naznačených L-K násobení lze vykonat jako poslední, pro každou takovou možnost určí počet provedených násobení čísel a z nich určí minimum:PocetNasobeni (K, L) = min ( PocetNasobeni (K, i) +i = K, …, L-1PocetNasobeni (i+1, L) + PK-1 . Pi . PL ) Programování - 23

  23. function PocetNasobeni(K, L: integer): integer;var Poc: integer; {k určení počtu násobení} Min: integer; {minimální počet násobení} i: integer;beginif K = L then PocetNasobeni:=0 {úsek tvořen jedinou maticí, žádné násobení se neprovádí}elsebegin Min:=maxint;for i:=K to L-1 do {"poslední" násobení za i-tou maticí}begin Poc:=PocetNasobeni(K,i) + PocetNasobeni(i+1,L) {násobení v úsecích} + P[K-1] * P[i] * P[L]; {poslední násobení}if Poc < Min then Min:=Pocend; PocetNasobeni:=Minendend; {function PocetNasobeni} Programování - 23

  24. Příčina neefektivity:pro mnohé dvojice K, L se počítá PocetNasobeni (K, L) opakovaně vícekrát Odstranění neefektivity:již jednou spočítané hodnoty PocetNasobeni (K, L) si budeme pamatovat v poli a nebudeme je počítat opakovaněVýsledná složitost:každou hodnotu PocetNasobeni (K, L) budeme počítat jen jednou, těchto hodnot je O(N2) a výpočet každé z nich má časovou složitost O(N)  časová složitost algoritmu O(N3) Realizace:buď „chytrá rekurze“ (tzn. doplnění rekurzivního algoritmu polem), nebo výpočet zdola bez rekurze dynamickým programováním Programování - 23

  25. Řešení dynamickým programováním:Mi, j = minimální počet násobení potřebný k výpočtu součinui po sobě jdoucích matic počínaje maticí Aj tzn. Aj . Aj + 1 . … . Aj + i - 1Hodnoty Mi, j jsou definovány pro každé i od 1 do N,vždy pro j od 1 do N-i+1.M1, j = 0 pro všechna j od 1 do NMN, 1 = výsledek (minimální počet násobení čísel potřebný k vynásobení všech N zadaných matic)Mi, j ukládáme do matice M[1..N, 1..N]Hodnoty matice počítáme po řádcích (s rostoucím i):první řádek – triviální – samé 0i-tý řádek (pro i > 1) – spočítáme pomocí hodnot na řádcích 1 až i-1 Programování - 23

  26. Mi, j = min ( Mk, j + Mi - k, j + k + Pj - 1 . Pj + k - 1 . Pj + i - 1 )k=1,…,i-1 počet matic součinsoučinposlednívlevo od Aj ... Aj + k - 1Aj + k … Aj + i – 1násobení„posledního“násobeníEfektivita algoritmu:- paměťová složitost O(N2) – matice M velikosti N x N- časová složitost O(N3) – výpočet každého prvku matice M má složitost O(N) Programování - 23

  27. Implementace:for j:=1 to N do M[1,j]:=0;for i:=2 to N do {řádky matice M}for j:=1 to N-i+1 dobegin Min:=maxint;for k:=1 to i-1 dobegin Poc:=M[k,j] + M[i-k,j+k] {násobení v úsecích} + P[j-1] * P[j+k-1] * P[j+i-1]; {poslední násobení}if Poc < Min then Min:=Pocend; M[i,j]:=Minend; Programování - 23

  28. Určení vhodného uzávorkování:- použijeme druhé pole D[1..N, 1..N]- hodnoty Di, j určujeme zároveň s hodnotami Mi, j- Di, j = k, pomocí něhož je určeno minimální Mi, j- správné uzávorkování zrekonstruujeme zpětně z obsahu pole D počínaje od DN, 1 Programování - 23

  29. Minimální triangulaceKonvexní N-úhelník A1 A2 … AN (N > 3) je zadán kartézským souřadnicemi svých vrcholů v rovině.diagonála = spojnice dvou vrcholů, které spolu nesousedí na obvodutriangulace = soubor neprotínajících se diagonál, které rozdělují plochu N-úhelníka na samé trojúhelníky (existuje více triangulací, každá je tvořena N-3 diagonálami)velikost triangulace = součet délek všech diagonál tvořících triangulaciminimální triangulace = ta z triangulací, která má minimální velikostÚkol: nalézt minimální triangulaci daného N-úhelníka.Nejprve budeme hledat pouze velikost minimální triangulace,později doplníme i určení diagonál, které ji tvoří. Programování - 23

  30. Řešení – dynamické programováníPostupujeme zdola od minimálních triangulací malých mnohoúhelníků, z nich sestavujeme minimální triangulace větších a větších mnohoúhelníků, až najdeme minimální triangulaci celého zadanéhoN-úhelníka.Mi, j = velikost minimální triangulace mnohoúhelníka tvořeného i po sobě jdoucími vrcholy na obvodu daného N-úhelníka počínaje vrcholem Aj , tzn. mnohoúhelníka Aj Aj + 1 … Aj + i - 1 , zvětšená navíc o velikost úsečky Aj Aj + i – 1Indexy vrcholů zde chápeme cyklicky, tzn. AN+1 = A1, AN+2 = A2 , atd. Programování - 23

  31. Hodnoty Mi, j jsou definovány pro všechna i od 3 do N-1 a pro všechna j od 1 do N.M3, j = | Aj Aj + 2| pro všechna j od 1 do NMN-1, j = velikost minimální triangulace celého N-úhelníka takové, která obsahuje diagonálu Aj Aj + N - 2 minimum z těchto hodnot je výsledkem úlohy Mi, j ukládáme do matice M[2..N-1, 1..N]Hodnoty matice počítáme po řádcích (s rostoucím i):M2, j = 0 – triviální (definujeme formálně z technických důvodů) M3, j = | Aj Aj + 2| pro všechna j od 1 do N – plyne přímo z definicei-tý řádek (pro i > 3) – spočítáme pomocí hodnot na řádcích 3 až i-1 Programování - 23

  32. Výpočet Mi, j :- každá triangulace i-úhelníka Aj Aj + 1 … Aj + i - 1 musí obsahovat dvojici úseček Aj Aj + k a Aj + k Aj + i - 1 pro nějaké k od 1 do i-2(neboť musí existovat právě jeden trojúhelník se stranou Aj Aj + i - 1, ten má třetí vrchol nutně v nějakém bodě Aj + k)- zkoušíme tedy možnosti pro všechna taková k, velikost triangulace vždy spočítáme z již známých minimálních triangulací menších mnohoúhelníkůMi, j = min ( Mk + 1, j + Mi - k, j + k ) + délka (Aj Aj + i - 1 ) k=1,…,i-2Efektivita algoritmu:- paměťová složitost O(N2) – matice M velikosti N x N- časová složitost O(N3) – výpočet každého prvku matice M má složitost O(N) Programování - 23

  33. Určení seznamu diagonál:- použijeme druhé pole D[1..N, 1..N]- hodnoty Di, j určujeme zároveň s hodnotami Mi, j- Di, j = k, pomocí něhož je určeno minimální Mi, j- seznam diagonál použitých v minimální triangulaci zrekonstruujeme zpětně z obsahu pole D počínaje od hodnoty DN-1, x , pokud MN-1, x je výsledkem úlohy (tzn. minimální prvek na řádku N-1 matice M)- tato fáze výpočtu má lineární časovou složitost Programování - 23

More Related