Programowanie dynamiczne
Transkrypt
Programowanie dynamiczne
Notatki z AiSD. Nr 6. Programowanie dynamiczne Opracowaª: Krzysztof Lory± IIUWr. II rok informatyki. 1 4 kwietnia 2014 Wst¦p Zastosowanie metody Dziel i Zwyci¦»aj do problemów zdeniowanych rekurencyjnie jest w zasadzie ograniczone do przypadków, gdy podproblemy, na które dzielimy problem, s¡ niezale»ne. W przeciwnym razie metoda ta prowadzi do wielokrotnego obliczania rozwi¡za« tych samych podproblemów. Jednym ze sposobów zaradzenia temu zjawisku jest tzw. spami¦tywanie, polegaj¡ce na pami¦taniu rozwi¡za« podproblemów napotkanych w trakcie oblicze«. W przypadku, gdy przestrze« wszyst- kich mo»liwych podproblemów jest niedu»a, efektywniejsze od spami¦tywania mo»e by¢ zastosowanie metody programowania dynamicznego. Polega ona na obliczaniu rozwi¡za« dla wszystkich podproblemów, pocz¡wszy od podproblemów najprostszych. Przykªad 1. Problem: Dane: Wynik: Liczby naturalne n, k . n k . n n n−1 n−1 k korzysta z zale»no±ci k = k−1 + k . Zastosowanie metody Dziel i Zwyci¦»aj byªoby jednak w tym przypadku nierozwa»ne, poniewa» w trakcie n−1 n−1 liczenia wywoªywaliby±my rekurencyjnie procedur¦ dla tych samych danych (tj. dla k−1 jak i k n − 2 i k − 1), co w konsekwencji prowadzi do tego, »e niektóre podproblemy byªyby rozwi¡zywane Naturalna metoda redukcji problemu obliczenia wykªadnicz¡ liczb¦ razy. Poni»sza procedura unika tego wykorzystuj¡c tablic¦ tab[1..n, 1..k] do spa- mi¦tywania. for i=1 to n do for j = 0 to k do tabi,j ←00 ?00 .................. function nPOk(n, k) if k = n or k =00000then tabk,n ← 1; return 1; if tabn−1,k−1 = ? then tabn−1,k−1 ←nPOk(n − 1, k − 1) if tabn−1,k =00 ?00 then tabn−1,k ←nPOk(n − 1, k) tabn,k = tabn−1,k−1 + tabn−1,k tabn,k return Rekurencyjne obliczanie n k z u»yciem spami¦tywania Za zastosowaniem w tym przypadku programowania dynamicznego przemawia fakt, i» liczba ró»- n k jest niewielka, a mianowicie 2 O(n ). Podobnie jak w metodzie spami¦tywania, algorytm dynamiczny oblicza pocz¡tkowy fragment nych podproblemów, jakie mog¡ pojawi¢ si¦ w trakcie obliczania trójk¡ta Pascala i umieszcza go w tablicy tab. W przeciwie«stwie jednak do poprzedniej metody, która jest metod¡ top-down i jest implementowana rekurencyjnie, algorytm dynamiczny jest metod¡ bottom-up i jest implementowany iteracyjnie. To pozwala w szczególno±ci na wyeliminowanie kosztów zwi¡zanych z obsªug¡ rekursji. 1 for i = 1 to n do tabi,0 ← 1 .................. function nPOk(n, k) for j = 1 to k do tabj,j ← 1 i=j+1 tabn,k for return Obliczanie n k to n do tabi,j ← tabi−1,j−1 + tabi−1,j metod¡ programowania dynamicznego Fakt, »e metoda programowania dynamicznego oblicza w sposób systematyczny rozwi¡zania wszystkich podproblemów, pozwala cz¦sto na poczynienie dodatkowych oszcz¦dno±ci w stosunku do metody spami¦tywania. W tym przykªadzie mo»emy znacznie zredukowa¢ koszty pami¦ciowe. Jak ªatwo zauwa»y¢, obliczenie kolejnej przek¡tnej trójk¡ta Pascala wymaga znajomo±ci jedynie warto±ci z poprzedniej przek¡tnej. Tak wi¦c zamiast tablicy n×k wystarcza tablica n × 2, a nawet tablica n × 1. 2 Podobnie jak w przypadku metody dziel i zwyci¦»aj, kluczem do zastosowania programowania dynamicznego jest znalezienie takiego sposobu dzielenia problemu na podproblemy, by optymalne rozwi¡zanie problemu mo»na byªo w prosty sposób otrzyma¢ z optymalnych rozwi¡za« podproblemów. Wskazaniem na zastosowanie wówczas programowania dynamicznego a nie metody dziel i zwyci¦»aj jest sytuacja, gdy sumaryczny rozmiar podproblemów jest du»y. Oczywi±cie, jak ju» wspominali±my, aby algorytm dynamiczny byª efektywny, przestrze« wszystkich mo»liwych podproblemów nie mo»e by¢ zbyt liczna. Przykªad 2. Problem: {ai,j } liczb nieujemnych (i Dane: Tablica Wynik: Ci¡g indeksów Pm j=1 i1 , . . . , im taki, »e = 1, . . . , n; j = 1, . . . , m) ∀j=1,...,m−1 |ij − ij+1 | ≤ 1, minimalizuj¡cy sum¦ aij ,j Interpretacja: Ci¡g kolumny tablicy a. i1 , . . . , i m wyznacza tras¦ wiod¡c¡ od pierwszej do ostatniej Startujemy z dowolnego pola pierwszej kolumny i ko«czymy na dowolnym polu ostatniej kolumny. W ka»dym ruchu przesuwamy si¦ o jedno pole: albo w prawo na wprost albo w prawo na ukos (jak pokazano na rysunku 1). Chcemy znale¹¢ tras¦ o minimalnej dªugo±ci rozumianej jako suma liczb z pól znajduj¡cych si¦ na trasie. Rysunek 1: Mo»liwe kierunki ruchu w tablicy a. Jak ªatwo sprawdzi¢ liczba wszystkich prawidªowych tras jest wykªadnicza, wi¦c rozwi¡zanie siªowe nie wchodzi w rachub¦. 2 Rozwa»my najpierw nieco prostsze zadanie, polegaj¡ce na znalezieniu dªugo±ci optymalnej trasy. Potem poka»emy w jaki sposób zorganizowa¢ obliczenia, by wyznaczenie samej trasy byªo proste. di,k oznacza minimaln¡ dªugo±¢ trasy wiod¡cej od dowolnego pola pierwszej kolumny do pola P (i, k) - problem wyznaczenia di,k . Rozwi¡zanie P (i, k) (dla k > 1) mo»na ªatwo otrzyma¢ z rozwi¡za« trzech prostszych podproblemów, a mianowicie P (i − 1, k − 1) , P (i, k − 1) i P (i + 1, k − 1) (w przypadku P (1, k) i P (n, k) - dwóch podproblemów). Problem speªnia wi¦c wymagane kryterium Niech ai,k , a optymalno±ci. Je±li za rozmiar P (i, k) k −1. problemów rozmiaru przyjmiemy warto±¢ k, to problem rozmiaru k redukujemy do trzech pod- To zbyt skromna redukcja, by stosowa¢ metod¦ dziel i zwyci¦»aj. Z drugiej strony przestrze« wszystkich podproblemów jest stosunkowo niewielka - skªada si¦ z (zawiera wszystkie P (i, j) dla i = 1, . . . , n, j = 1, . . . , m), nm elementów mo»emy wi¦c zastosowa¢ programowanie dynamiczne. for j = 1 to m do d0,j ← dn+1,j ← ∞ for i = 1 to n do di,1 ← ai,1 for j = 2 to m do for i = 1 to n do di,j ← ai,j + min{di−1,j−1 , di,j−1 , di+1,j−1 } return min{di,m | i = 1, . . . , n} Pozostaje wyja±ni¢, w jaki sposób mo»na odtworzy¢ optymaln¡ tras¦. Niech i, dla której osi¡gane jest trasy. min{di,m | i = 1, . . . , n}, a wi¦c ai0 ,m i0 b¦dzie warto±ci¡ jest ostatnim polem optymalnej Aby wyznaczy¢ przedostatnie pole wystarczy sprawdzi¢, która z trzech warto±ci j ∈ {i0 − 1, i0 , i0 + 1}) dj,m−1 (dla jest minimalna. Post¦puj¡c dalej rekurencyjnie wyznaczymy caª¡ tras¦. procedure trasa(i, j) { if j = 1 then return i if di−1,j−1 < di,j−1 then k ← i − 1 else k ← i if dk,j−1 < di+1,j−1 then k ← i + 1 return concat(trasa(k, j − 1), i) } .................. write(trasa(i0 , m)) 2 Programowanie dynamiczne jest cz¦st¡ metod¡ rozwi¡zywania problemów optymalizacyjnych. Przykªad 2 stanowi ilustracj¦ klasycznego sposobu rozwi¡zania takiego problemu: najpierw znajdujemy warto±¢ optymalnego rozwi¡zania a dopiero potem, na podstawie wylicze« tej warto±ci, konstruujemy optymalne rozwi¡zanie. 2 2.1 Dalsze przykªady Najdªu»szy wspólny podci¡g. 2.1.1 Denicja problemu Denicja 1 Ci¡g Z = hz1 , z2 , . . . , zk i jest podci¡giem ci¡gu X = hx1 , x2 , . . . , xn i, je±li istnieje ±ci±le rosn¡cy ci¡g indeksów hi1 , i2 , . . . , ik i (1 ≤ ij ≤ n) taki, »e ∀j=1,2,...k xij = zj . 3 Je±li Z ci¡gów jest podci¡giem zarówno ci¡gu X X jak i ci¡gu Y, to mówimy, »e Z jest wspólnym podci¡giem Y. i Konwencja: Dla wygody, w dalszej cz¦±ci ci¡gi b¦dziemy traktowa¢ jako napisy nad ustalonym al- fabetem. Przykªad: 'BABA' jest wspólnym podci¡giem ci¡gów 'ABRACADABRA' i 'RABARBAR', ale nie jest ich najdªu»szym wspólnym podci¡giem (dªu»szym jest np. 'RAAAR'). 2 Oznaczenia: • LCS(X, Y ) = {Z | Z • przez Xi jest wspólnym podci¡giem oznaczamy i-literowy preks ci¡gu szczególno±ci przez X0 X i o maksymalnej dªugo±ci} Y X = hx1 , x2 , . . . , xn i, tj. podci¡g hx1 , x2 , . . . , xi i; w oznaczamy ci¡g pusty. Problem: X = hx1 , x2 , . . . , xm i i Y = hy1 , y2 , . . . , yn i Z z LCS(X, Y ) Dane: ci¡gi Wynik: dowolny ci¡g 2.1.2 Redukcja problemu Problem znalezienia ci¡gu Z z LCS(X, Y ) mo»emy zredukowa¢ do prostszych problemów na podstawie nast¦puj¡cej obserwacji: • ka»dego ci¡gu z • X i ostatnia litera Y LCS(X, Y ). je±li ostatnia litera X je±li i Y s¡ takie same, to litera ta musi by¢ ostatnim elementem ró»ni¡ si¦ na ostatniej pozycji (tj, na ostatniej pozycji ma liter¦ ró»n¡ od pozycji ma liter¦ ró»n¡ od xm xm 6= yn ), LCS(X, Y ), LCS(X, Y ), który który na ostatniej yn . W pierwszym przypadku problem znalezienia ci¡gu z LCS(Xm−1 , Yn−1 ). znalezienia ci¡gu z to istnieje ci¡g w lub istnieje ci¡g w LCS(Xm , Yn ) redukujemy do podproblemu Rozwi¡zaniem b¦dzie konkatenacja znalezionego ci¡gu i ostat- X -a. W drugim przypadku problem redukujemy do dwóch podproblemów: znalezienie LCS(Xm−1 , Yn ) i znalezienie ci¡gu z LCS(Xm , Yn−1 ). W tym przypadku rozwi¡zaniem b¦- niej litery ci¡gu z dzie dªu»szy ze znalezionych ci¡gów. 2.1.3 Algorytm Najpierw koncentrujemy si¦ na obliczeniu warto±ci rozwi¡zania optymalnego, któr¡ w tym przypadku jest dªugo±¢ elementów z LCS(X, Y ). Sposobu na obliczenie tej warto±ci dostarcza nam obserwacja poczyniona w poprzednim paragrae. Fakt 1 Niech di,j oznacza dªugo±¢ elementów z di,j LCS(Xi , Yj ). 0 1 + di−1,j−1 = max(di,j−1 , di−1,j ) je±li je±li je±li Wówczas: i = 0 lub j = 0, i, j > 0 i xi = yj , i, j > 0 i xi 6= yj 2 Tablic¦ d mo»emy oblicza¢ kolejno wierszami (lub kolumnami), a wynik odczytamy z 4 dm,n . Procedure LCS(Xm , Yn ) for i ← 1 to m do di,0 ← 0 for j ← 0 to n do d0,j ← 0 for i ← 1 to m do for j ← 1 to n do if xi = yj then di,j ← 1 + di−1,j−1 else di,j ← max{di−1,j , di,j−1 } Aby wypisa¢ jaki± element z LCS musimy przej±¢ tablic¦ d jeszcze raz, pocz¡wszy od elementu dn,m , w podobny sposób jak to robili±my w Przykªadzie 2. Je±li zale»y nam na szybko±ci algorytmu, mo»emy nieco przyspieszy¢ t¦ jego faz¦. W tym celu, w trakcie obliczania tablicy d, gólnych elementów tablicy mo»emy w dodatkowej tablicy zapami¦tywa¢ drog¦ doj±cia do poszcze- d. Elementy dodatkowej tablicy przyjmowaªyby jedn¡ z trzech ró»nych warto±ci, w zale»no±ci od tego czy di−1,j , di,j powstaª przez dodanie czy te» wreszcie przez przepisanie 1 do di−1,j−1 , czy przez przepisanie di,j−1 . 2.1.4 Koszt algorytmu d odbywa si¦ w czasie staªym. Tak wi¦c caªkowity Θ(n · m). Koszt skonstruowania najdªu»szego podci¡gu na Obliczenie ka»dego elementu tablicy koszt wy- d podstawie peªnienia tablicy tablicy 2.2 d jest równy jest liniowy. Wyznaczanie optymalnej kolejno±ci mno»enia macierzy. 2.2.1 Denicja problemu Mamy obliczy¢ warto±¢ wyra»enia M postaci M1 ×M2 ×· · ·×Mn , gdzie Mi s¡ macierzami. Zakªadamy, Mi jest równa liczbie wierszy macierzy Mi+1 »e wyra»enie jest poprawne, tj. liczba kolumn macierzy (dla i = 1, . . . , n − 1). Poniewa» mno»enie macierzy jest dziaªaniem ª¡cznym, warto±¢ M mo»emy liczy¢ na wiele sposo- bów. Wybór sposobu mo»e w istotny sposób wpªyn¡¢ na liczb¦ operacji skalarnych jakie wykonamy podczas oblicze«. Przykªad Niech macierze M1 , M2 , M3 maj¡ wymiary odpowiednio d × 1, 1 × d i d × 1. Rozwa»my dwa sposoby obliczenia ich iloczynu: • (M1 × M2 ) × M3 W wyniku pierwszego mno»enia otrzymujemy macierz d × d, wi¦c jego koszt (niezale»nie od d2 . W drugim mno»eniu tak»e musimy przyj¦tej metody mno»enia macierzy) wynosi co najmniej wykona¢ Θ(d2 ) operacji. • M1 × (M2 × M3 ) Koszt obliczenia M2 × M3 wynosi O(d). W O(d). jego wyniku otrzymujemy macierz 1 × 1, wi¦c koszt nast¦pnego mno»enia wynosi tak»e 1 Dalsze rozwa»ania b¦dziemy przeprowadza¢ przy nast¦puj¡cym zaªo»eniu : Koszt pomno»enia macierzy o wymiarach a × b i b × c wynosi abc. 1 Jest to koszt mno»enia wykonanego metod¡ tradycyjn¡; pó¹niej poznamy inne, szybsze metody. 5 2 Problem: Dane: d0 , d1 , . . . , dn - liczby naturalne di−1 × di Interpretacja: Zadanie: Mi . - wymiar macierzy Wyznaczy¢ kolejno±¢ mno»enia macierzy M1 × M2 × · · · × Mn , przy której koszt obliczenia tego iloczynu jest minimalny. 2.2.2 Rozwi¡zanie siªowe Rozwi¡zanie siªowe, polegaj¡ce na sprawdzeniu wszystkich mo»liwych sposobów wykonania oblicze«, jest nieakceptowalne. Liczba tych sposobów dana jest wzorem S(n) = 1 Pn−1 i=1 Uzasadnienie wzoru: Ka»de z n−1 je±li S(i)S(n − i) je±li mno»e« wyst¦puj¡cych w ci¡gu n=1 n>1 M1 × . . . × Mn , mo»e by¢ ostatnim, jakie wykonamy obliczaj¡c ten iloczyn. Liczba sposobów mno»enia macierzy, w których i-te mno»enie jest ostatnim, jest równa iloczynowi (tj. liczby sposobów, na które mo»na pomno»y¢ S(i) · S(n − i) macierzy oraz liczby sposobów, na które mo»na pomno»y¢ Rozwi¡zaniem powy»szego równania jest n−i S(n) ="n−ta i pierwszych ostatnich macierzy). liczba Catalana"= ! n−2 1 2 n n−1 n = Ω( 4n2 ). Tak wi¦c koszt sprawdzania wszystkich mo»liwych iloczynów jest wykªadniczy. 2.2.3 Rozwi¡zanie dynamiczne k -te mno»enie jest ostatnim M1 × . . . × Mk oraz Mk+1 × . . . × Mn Zauwa»amy, »e problem speªnia kryterium optymalno±ci. Je±li bowiem jakie wykonamy w optymalnym sposobie oblicze«, to iloczyny te» musiaªy by¢ obliczone w optymalny sposób. Na podstawie tej wªasno±ci mo»emy uªo»y¢ nast¦puj¡cy algorytm rekurencyjny wyznaczaj¡cy optymalny koszt oblicze«. function matmult(i, j) if i = j then return 0 opt ← ∞ k←i j−1 opt ← min(opt, dj−1 dk dj + matmult(i, k) + matmult(k + 1, j)) opt for to do return n )). (i, j). Algorytm ten, jakkolwiek szybszy od metody siªowej, nadal dziaªa w czasie wykªadniczym (Θ(3 Przyczyna tkwi w wielokrotnym wykonywaniu oblicze« dla tych samych warto±ci parametrów Unikniemy tego mankamentu stosuj¡c programowanie dynamiczne. Niech mi,j = minimalny koszt obliczenia Dla wygody przyjmujemy, »e mi,j = 0 (dla i ≥ j ). Mi × Mi+1 × · · · × Mj ” Wówczas mi,j = min (mi,k + mk+1,j + di−1 dk dj ). i≤k<j Skªadnik mi,k jest kosztem obliczenia Mi × Mi+1 × · · · × Mk , skªadnik mk+1,j - kosztem obliczenia Mk+1 × Mk+2 × · · · × Mj , natomiast di−1 dk dj to koszt obliczenia iloczynu dwóch powstaªych macierzy. 6 procedure dyn − matmult(d[0..n]); intm[1..n, 1..n], p[1..n, 1..n] for i ← 1 to n do mii ← 0; for s ← 1 to n − 1 do for i ← 1 to n − s do j ←i+s mij ← mini≤k<j (mi,k + mk+1,j + di−1 dk dj ) pij ← "to k, przy którym osi¡gane byªo minimum dla mij " p[1..n, 1..n] return Algorytm oblicza warto±ci mi,i+s (na podstawie powy»szego wzoru) oraz warto±ci pi,i+s , które umo»liwiaj¡ pó¹niejsze skonstruowanie rozwi¡zania. Koszt algorytmu. Tablic¦ mi,j Koszt policzenia jednego elementu znajduje si¦ n−s liczymy przek¡tna za przek¡tn¡ pocz¡wszy od gªównej przek¡tnej. mi,i+l na s-tej przek¡tnej wynosi Θ(s). Poniewa» na s-tej przek¡tnej elementów, koszt algorytmu wynosi T (n) = n−1 X Θ(s) · (n − s) = Θ(n3 ). s=0 Odtworzenie rozwi¡zania stawie tablicy p. Odtworzenia rozwi¡zania dokonujemy w standardowy sposób na pod- Zwró¢ uwag¦, »e znalezienie rozwi¡zania na podstawie samych tylko warto±ci wymagaªoby czasu Θ(n2 ). 7 mij