Programowanie dynamiczne (optymalizacja dynamiczna).

Transkrypt

Programowanie dynamiczne (optymalizacja dynamiczna).
Programowanie dynamiczne (optymalizacja dynamiczna).
W wielu przypadkach zadania, których złożoność wynikająca z pełnego
przegl ą du jest du ż a (zwykle wyk ł adnicza) mo ż na rozwi ą za ć w czasie
wielomianowym stosując metodę optymalizacji dynamicznej.
Programowanie dynamiczne - metoda znajdowania rozwiązań problemów
optymalizacyjnych podobna do metody „dziel i zwyciężaj”- w metodzie tej
zadany problem dzielimy na podproblemy, rozwiązujemy je, a następnie łączymy
rozwiązania podproblemów.
•metoda
„dziel i zwyciężaj” - wielokrotnie rozwiązuje ten sam problem,
wykonuje więc dużo więcej pracy
•programowanie dynamiczne - algorytm oparty na tej metodzie rozwiązuje
każdy podproblem tylko jeden raz zapamiętując wynik, unika się w ten sposób
wielokrotnych obliczeń dla tego samego podproblemu
Barbara Marszał-Paszek
Rozpatrzmy rekurencyjny algorytm obliczający ciąg
Fibonacciego:
Fib(0)= 0
Fib(1)=1
Fib(n)= Fib(n-1)+Fib(n-2) dla n≥2
int Fib( int n ) {
if( n < 1 ) return 0;
if( n == 1 ) return 1;
return Fib(n-1) + Fib(n-2);
}
[Fib(5)] = Fib(4) + Fib(3)
[Fib(4)] = Fib(3) + Fib(2)
[Fib(3)] = Fib(2) + Fib(1)
[Fib(3)] = Fib(2) + Fib(1)
[Fib(2)] = Fib(1) + Fib(0)
[Fib(2)] = Fib(1) + Fib(0)
[Fib(2)] = Fib(1) + Fib(0)
Barbara Marszał-Paszek
Algorytm rekurencyjny mo ż na poprawi ć wykorzystuj ą c tak zwane
"zapamiętywanie".
Wykorzystujemy w tym celu tablicę zawierającą już obliczone wartości:
int fib[MAX]; // inicjujemy ją, aby oznaczyć wszystkie wartości jako "nieznane"
for( i= 0; i < MAX; i++ )
fib[i]= -1;
int Fib( int n }{
if ( n < 1 ) return 0;
if ( n == 1 ) return 1;
if ( fib[n] == -1 ) fib[n]= Fib(n-1) + Fib(n-2);
return fib[n];
}
Barbara Marszał-Paszek
Etapy programowania dynamicznego
•
•
•
•
Scharakteryzowanie struktury optymalnego rozwiązania
Rekurencyjne zdefiniowanie kosztu optymalnego rozwiązania.
Obliczenie optymalnego kosztu metodą wstępującą.
Konstruowanie optymalnego rozwiązania na podstawie wcześniejszych
obliczeń.
Problem:
Dla danego ciągu n macierzy <A1, A2, ..., An>, gdzie dla i=1, 2, ..., n
macierz Ai ma wymiar pi-1 x pi, wyznaczyć taką kolejność mnożenia macierzy
A1· A2 ·...·An aby koszt obliczeń był jak najmniejszy.
Barbara Marszał-Paszek
Pseudokod standardowego algorytmu mnożenia dwóch macierzy
MNOŻENIE_MACIERZY(A,B) {
if ile_kolumn[A] ≠ ile_wierszy[B] then error
else {
for i=1 to ile_wierszy[A]
for j=1 to ile_kolumn[B] do {
C[i,j]:=0
for k=1 to ile_kolumn[A] do
C[i,j]:=C[i,j]+A[i,k]·B[k,j]
}
return C
}
}
Barbara Marszał-Paszek
Obserwacja:
Czas obliczeń jest zdeterminowany przez ilość mnożeń skalarnych.
Jeśli A i B są macierzami o rozmiarze odpowiednio p x q i q x r, to ilość mnożeń
wynosi pqr.
Przykład:
A1 o rozmiarze 10 x 100
A2 o rozmiarze 100 x 5
A3 o rozmiarze 5 x 50
Ile mnożeń skalarnych?
• ((A1A2)A3)10 x 100 x 5 + 10 x 5 x 50 = 5000 + 2500 = 7500
• (A1(A2A3) 100 x 5 x 50 + 10 x 100 x 50 = 25000 + 50000=75000
Barbara Marszał-Paszek
Struktura optymalnego rozwiązania
Oznaczenie: Ai..j=Ai⋅Ai+1…·Aj
Obserwacja:
Umieszczenie nawiasów w podci ą gu A 1 A 2 … A k w optymalnym
nawiasowaniu A1A2… An jest optymalnym nawiasowaniem A1A2… Ak.
Dowód:
Gdyby istniało nawiasowanie A1A2… Ak o niższym koszcie, to w połączeniu
z optymalnym nawiasowaniem A1A2… An otrzymalibyśmy nawiasowanie
A1A2… Ak o koszcie niższym czyli sprzeczność.
Barbara Marszał-Paszek
Zdefiniowanie rekurencyjne kosztu optymalnego.
Podproblemy: wyznaczenie optymalnego nawiasowania iloczynów Ai⋅Ai+1…·Aj
gdzie 1 ≤ i ≤ j ≤ n
Oznaczenie: m[i, j] – minimalna liczba mnożeń skalarnych niezbędnych do
obliczenia macierzy Ai..j
Oznaczenie: s[i, j] – wartość k, która realizuje minimalną wartość m[i, j]
Niech dane wejściowe stanowi ciąg <p0, p1, ...,pn> rozmiarów macierzy, gdzie
d ł ugo ś ć [p]=n+1, u ż ywamy macierzy m[1..n,1..n] oraz s[1..n,1..n] do
zapamiętywania kosztów oraz indeksów k dających optymalny podział
Barbara Marszał-Paszek
MACIERZE_KOSZT(p)
n:=długość[p]-1
for i=1 to n do m[i, i]:=0
for w=2 to n do {
for i=1 to n-w+1 do {
j=i+w-1
m[i,j]:=∞
for k=i to j-1 do {
q:=m[i,k]+m[k+1,j]+pi-1pkpj
if q<m[i,j] then {
m[i,j]:=q,
s[i,j]:=k
}
}
}
}
return (m, s)
Barbara Marszał-Paszek
Konstruowanie optymalnego rozwiązania
MNOŻENIE_ŁAŃCUCHA_MACIERZY(A, s, i, j)
if j>i then
X:= MNOŻENIE_ŁAŃCUCHA_MACIERZY(A, s, i, s[i, j])
Y:= MNOŻENIE_ŁAŃCUCHA_MACIERZY(A, s, s[i, j]+1, j)
return MNOŻENIE_MACIERZY(X, Y)
else
return Ai
Barbara Marszał-Paszek
Charakterystyczne elementy metody programowania
1.Problem wykazuje optymalną podstrukturę, jeśli jego optymalne rozwiązanie
jest funkcją optymalnych rozwiązań podproblemów; metoda dowodzenia jest
następująca: zakładamy, że jest lepsze rozwiązanie podproblemu, po czym
pokazujemy, iż to założenie zaprzecza optymalności rozwiązania całego
problemu
2.„Rozsądnie mała” przestrzeń istotnie różnych podproblemów. Mówimy, że
problem ma w ł asno ś ć wspólnych podproblemów, je ś li algorytm
rekurencyjny wielokrotnie oblicza rozwiązanie tego samego podproblemu bo
algorytmy oparte na programowaniu dynamicznym rozwiązują dany
podproblem tylko jeden raz i zapamiętują gotowe rozwiązania, które potem
wystarczy odczytać w stałym czasie.
Jeśli problem wykazuje te własności warto spróbować, czy daje się stosować
metoda programowania dynamicznego.
Barbara Marszał-Paszek
PROBLEM NAJDŁUŻSZEGO WSPÓLNEGO PODCIĄGU
(Problem LCS)
Problem znalezienia Najdłuższego Wspólnego Podciągu (LCS – Longest Common
Subsequences) pojawia się w kilku praktycznych zastosowaniach :
1.Poszukiwanie ”podobieństwa” dwóch pary nici DNA jako jednej z miar
stopnia pokrewieństwa odpowiadających im organizmów
2.Wy ł apywanie plagiatów muzycznych poprzez analiz ę ich linii
melodycznych
3.Porównywanie zawartości plików
4.Kryptografii
Najefektywniejsza metoda jego rozwiązania opiera się na programowaniu
dynamicznym.
Barbara Marszał-Paszek
Dane są ciągi:
X = <x1, x2, ..., xm> i Y = <y1, y2, ..., yn>.
Problem: Znaleźć najdłuższy wspólny podciąg ciągów X i Y.
Jak działa algorytm wyczerpujący?
•
•
•
•
Bierzemy krótszy z ciągów (załóżmy, że jest to X),
generujemy wszystkie podciągi ciągu X,
sprawdzamy, który podciąg jest też podciągiem Y,
zapamiętujemy najdłuższy podciąg.
Ile jest podciągów ciągu X?
Każdy podciąg ciągu X jest jednoznacznie wyznaczony przez pewien podzbiór
zbioru {1, 2, ..., m}, zatem ilość podciągów jest równa ilości podzbiorów zbioru
{1, 2, .., m}, czyli 2m. Czyli razem ze sprawdzeniem O(2mn).
Wniosek: algorytm wyczerpujący ma złożoność wykładniczą !.
Barbara Marszał-Paszek
Struktura optymalnego rozwiązania
Na szczęście ten problem ma własność optymalnej podstruktury i naturalna
przestrzeń podproblemów odpowiada w tym przypadku parom ”prefiksów”
ciągów wejściowych.
Oznaczenie:
Niech X = <x1, x2, ..., xm> i Xi = <x1, x2, ..., xi> dla i=0,1,2,...,m będzie i-tym
prefiksem ciągu X, przy czym Xo jest ciągiem pustym.
Twierdzenie (o optymalnej podstrukturze NWP)
Niech X = <x1, x2, ..., xm> i Y= <y1, y2, ..., yn> oraz niech Z = <z1, z2, ..., zk>
będzie NWP ciągów X i Y. Wtedy:
• jeśli xm = yn, to zk= xm=yn oraz Zk-1 jest NWP(Xm-1, Yn-1)
• jeśli xm ≠ yn i zk ≠ xm, to Z jest NWP(Xm-1 ,Y),
• jeśli xm ≠ yn i zk ≠ yn, to Z jest NWP(X, Yn-1).
Barbara Marszał-Paszek
Rekurencyjne zdefiniowanie kosztu optymalnego rozwiązania
Obserwacja: Z twierdzenia wynika, że aby obliczyć NWP(X, Y) trzeba rozwiązać
jeden lub dwa podproblemy:
•jeżeli xm = yn, to znajdujemy NWP(Xm-1, Yn-1), a następnie dołączając xm=yn
otrzymujemy NWP(X, Y)
•jeżeli xm ≠ yn, to znajdujemy NWP(Xm-1, Y) oraz NWP(X, Yn-1), a następnie
wybierając dłuższy z nich otrzymujemy NWP(X, Y)
Barbara Marszał-Paszek
Oznaczenie: c[i, j] – długość NWP(Xi, Yj)
Uwaga: jeśli i=0 lub j=0, to c[i, j]=0
Wniosek:
Barbara Marszał-Paszek
Obliczanie długości NWP
Obserwacja 1: Jest O(mn) rożnych podproblemów problemu NWP.
Dowód: X ma długość m, Y ma długość n
Obserwacja 2: Problem NWP ma własność wspólnych podproblemów.
Dowód: Aby znaleźć NWP(X, Y) możemy potrzebować NWP(Xm-1, Y) oraz
NWP(X, Yn-1). Oba te podproblemy mogą zawierać wspólny podproblem
znalezienia NWP(Xm-1, Yn-1).
Wniosek: Można stosować programowanie dynamiczne.
dane wejściowe:
ciągi X i Y
c[1.. m, 1.. n ] - przechowuje wartości c[i, j]
b[1.. m, 1.. n] - b[i, j] wskazuje na pole w tablicy c odpowiadające
wybranemu podczas obliczeń c[i, j] optymalnemu rozwiązaniu podproblemu
Barbara Marszał-Paszek
NWP_Długość(X,Y){
m:=długość(X)
n:=długość(Y)
for i:=1 to m do c[i,0]:=0
for j:=1 to n do c[0,j]:=0
for i:=1 to m
for j:=1 to n
if xi=yjthen
{
c[i, j]:=c[i-1, j-1]+1;
b[i, j]:=„↖”
}
else if c[i-1, j] ≥ c[i, j-1] then
{
c[i, j]:=c[i-1, j];
b[i, j]:=„↑”
}
else {
c[i, j]:=c[i, j-1];
b[i, j]:=„←”
}
return c i b
}
Barbara Marszał-Paszek
Przykład:
X = <A, B, C, B, D, A, B>
Y = <B, D, C, A, B, A>
Rozwiązanie: <B, C, B, A>
Barbara Marszał-Paszek
Konstrukcja NWP na podstawie wcześniejszych obliczeń
Procedura Drukuj_NWP - wypisuje NWP(X, Y) korzystając z tablicy b, każda
strzałka typu „↖” w polu b[i, j] oznacza, że xi=yj należy do NWP
Drukuj_NWP(b, X, Y, i, j)
if i=0 lub j=0 then return;
if b[i, j]=„” then
{
Drukuj_NWP(b, X, Y, i-1, j-1);
wypisz xi
}
else
if b[i, j]=„↑” then
Drukuj_NWP(b, X, Y, i-1, j)
else
Drukuj_NWP(b, X, Y, i, j-1);
Obserwacja: Czas działania wynosi O(m*n)
Barbara Marszał-Paszek
Inne rozwiązania algorytmiczne tego samego problemu.
Wagner i Fisher 1974 zaproponowa ł rozwi ą zanie problemu LCS z
wykorzystaniem programowania dynamicznego przedstawiony wcześniej o
rozwiązaniu O(mn).
Hirschberg 1975 zaproponował metodę dziel i zwycię żaj w oparciu o
programowanie dynamiczne o złożoności czasowej O(n2) ale o pamięciowej tylko
O(n).
Hirschberg 1977 – O(pn) gdzie p to długość LCS
Hunt i Szymański 1977 – O(rlogn) gdzie r liczba wszystkich dopasowań.
Należy zwrócić uwagę, że te dwa algorytmy są efektywne dla p i r małych.
Niestety w najgorszym przypadku gdy p=n a r=n2 algorytmy osiągają wartości
O(n2) i O(n2logn) gorsze od standardowej metody opartej na programowaniu
dynamicznym.
Masek i Paterson 1980 zaproponowali algorytm O(n2/logn).
Barbara Marszał-Paszek
Allison i Dix 1986 (lub Crochemore 2001) zaproponowali algorytm oparty na
bitowej równoległości o złożoności obliczeniowej
gdzie w to rozmiar
słowa maszynowego.
Np. na 32-bitowej maszynie uzyskano szybszy o ok. 30 razy,
na 64- bitowej maszynie uzyskano szybszy o ok. 55 razy.
Barbara Marszał-Paszek

Podobne dokumenty