1 / 31

Algorytmy i struktury danych

Algorytmy i struktury danych. dziel i zwyciężaj programowanie dynamiczne algorytmy zachłanne. Dziel i zwyciężąj. Dzielimy problem na podproblemy (najlepiej o zbliżonych rozmiarach);

amora
Download Presentation

Algorytmy i struktury danych

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. Algorytmy i struktury danych dziel i zwyciężaj programowanie dynamiczne algorytmy zachłanne

  2. Dziel i zwyciężąj • Dzielimy problem na podproblemy (najlepiej o zbliżonych rozmiarach); • Znajdujemy rozwiązania podproblemów (powtarzając cały algorytm aż do uzyskania jednostkowych problemów); • uzyskane wyniki częściowe scalamy. Przykłady – duża liczba alg. rekurencyjnych m.in. • sortowanie szybkie; • slinia (rekurencja); • obliczanie wyrazów ciągu fibonacciego (rekurencja) * * Mniej efektywne niż inne podejścia.

  3. Dziel i zwyciężąj Problemy: • Duży koszt scalania rozwiązań podproblemów; • Duża ilość jednakowych podproblemów. Fib(n) = Fib(n-1) + Fib(n-2) = Fib(n-2) + Fib(n-3) + Fib(n-3) + Fib(n-4) = Fib(n-3) + Fib(n-4) + Fib(n-3) + Fib(n-3) + Fib(n-4) ….

  4. Programowanie dynamiczne Problemy: • Rekurencyjna definicja rozwiązania; • Konstrukcja optymalnego rozwiązania metodą począwszy od wyników cząstkowych

  5. Problem plecakowy - dyskretny Sformułowanie: Dla danego zbioru przedmiotów (opisanych przez wagę i cenę) i plecaka o rozmiarze K znaleźć upakowanie plecaka o największej wartości. Dysponujemy dowolną (lub ograniczoną) ilością przedmiotów każdego rodzaju. Przedmiotów nie wolno dzielić. Tj. dla Z = {(c1,w1, m1), (c2,w2,m2), (c3,w3,m3), …, (cn,wn,mn)} znaleźć podzbiór L = (l1, l2, …, ln), taki że å li*wi£ K, liÎ C+, li£ mi i å li*ci = max

  6. Problem plecakowy - dyskretny Przykład (bez limitów): Przedmioty (waga, cena): Z = { (1, 1), (2, 1), (3, 11), (4, 16), (5, 24) } Plecak: K = 7 Optymalne upakowanie: KN(K,Z) = 27 Liczby przedmiotów: L = (0, 0, 1, 1, 0)

  7. Problem plecakowy - dyskretny Rozwiązanie: • Podproblem – jeżeli podzielimy plecak na dwa mniejsze, to każdy z nich musi być optymalnie upakowany. • Wypełnij tablicę KN pomocniczą od 1 do K, wpisując do k-tej komórki KN(k) = max { ci + KN(k-wi); 1 £ i < n } . gdzie K – rozmiar plecaka, n- liczba przedmiotów • Oprócz wartości należy (np. w odrębnej tablicy) zapamiętywać jakie elementy zostały zapakowane.

  8. Problem plecakowy - dyskretny Nielimitowane przedmioty (1, 1) (2, 1)(3, 11) (4, 16) (5, 24)

  9. Alg. Problem plecakowy classGOOD:weight=0price=0 def Knapsack (goods,KSize) :KTmp = Array(KSize+1,0)for i in range(1,KSize):KTmp[i] = KTmp[i-1]for j in range(1, n+1):if Z[j].weight >= i and\ Z[j].price + KTmp[i-Z[j].weight] > KTmp[i]: KTmp[i] = Z[j].weight + KTmp[i-Z[j].weight] return KTmp[k]

  10. Mnożenie ciągu macierzy Sformułowanie: Dla danego ciągu macierzy <A1, A2, … An> tak dobrać tak kolejność operacji, aby zminimalizować ilość mnożeń. Reprezentacja danych: m[1, n] = minimalna liczba mnożeń potrzebnych do obliczenia A1* … *An

  11. Prosta implementacja mnożenia dwóch macierzy def MulMatrix(A, B):if Columns(A)!=Rows(B):ERROR else: for i in range(0, Rows(A)):for j in range(0, Columns(B)):C[i][j] = 0; for k in range(0, Columns(A)):C[i][j] += C[i][j]+ A[i][k]*B[k][j] return C

  12. Mnożenie ciągu macierzy Przykład: Dla danego ciągu macierzy <A1, A2, … An> tak dobrać kolejność operacji, aby zminimalizować ilość mnożeń. [p, q] ´ [q, r] = [p, r] O([p, q] ´ [q, r]) = p*q*r A1= [10, 100] A2= [100, 3] A3= [3, 50] O((A1´A2) ´ A3) = 10*100*3 + 10*3*50 = 4500 O(A1 ´ (A2´A3)) = 100*3*50 + 10*100*50 = 65000

  13. Mnożenie ciągu macierzy Rozwiązanie: • Podproblem – jeżeli podzielimy wyrażenie na dwa mniejsze w miejscu podziału "najwyższego" poziomu – nawiasowania w obu podwyrażeniach muszą być optymalne. • m[i, j] = { min (m[i, k]+m[k+1, j]+pi-1pkpj;i<=k<j } • Wypełnij tablicę m[i, j] poczynając od mnożenia par, potem trójek itd. • Oprócz wartości należy np. w odrębnej tablicy zapamiętywać jakie nawiasowanie zostało przyjęte za optymalne dla danej sytuacji

  14. Nieoptymalne rozwiązanie def RecursiveMatrixChain(p, i, j): if i == j: return 0 w = -1for k in (i,j+1):q = p[i-1]*p[k]*p[j]+RecursiveMatrixChain(p,i,k)+\ RecursiveMatrixChain(p[], k+1, j) if q<w: w = q return w RecursiveMatrixChain(p, 1, len-1)

  15. Mnożenie ciągu macierzy 15125 11875 9375 7875 15750 0 10500 7125 4375 2625 0 5375 2500 750 0 3500 1000 0 5000 0 0 3 3 3 1 1 0 3 3 3 2 0 3 3 3 0 5 4 0 5 0 0 j m 5 4 6 2 3 1 Rozwiązanie: A1= [30, 35] A2= [35, 15] A3= [15, 5] A4= [5, 10] A5= [10, 20] A6= [20, 25] 1 2 i 3 4 5 6 optdiv j 4 3 6 5 2 1 1 2 i 3 4 5 6

  16. Implementacja wyznaczania optymalnego nawiasowania def MatrixChain(p, len): for i in range(1,len): m[i][j] = 0 for h in range(2,len): for i in range(1,len-h-1): j = i+h-1m[i][j] = -1for k in range (i,j+1): tmp = m[i][k]+m[k+1][j] + p[i-1]*p[k]*p[j] if m[i][j] < 0 or tmp < m[i][j]:m[i][j] = tmpoptdiv[i][j] = k

  17. Rekur. implementacja wyznaczania optymalnego nawiasowania def RecursiveMatrixChain(p, i, j): if (i == j) return 0 m[i][j] = -1; for k in range(i,j) q = RecursiveMatrixChain(p,i,k)+\ RecursiveMatrixChain(p,k+1,j) + p[i-1]*p[k]*p[j]if m[i][j]<0 or q <= m[i][j]:m[i][j] = q return m[i][j] RecursiveMatrixChain(p[], 1, len-1);

  18. Spamiętywanie • Odmiana programowania dynamicznego; • Rekurencyjne podejście -> dziel i zwyciężaj; • Szybka pamięć dla rozwiązań chwilowych;

  19. Impl. mnożenia ciągu macierzyprzy wykorzyst. spamiętywania def MemorizedMatrixChain(p, len):for i in range(1,len): for j in range(1,len):m[i,j] = -1return LookupMatrixChain(p,1,len-1)

  20. Implementacja LookupMatrixChain def LookupMatrixChain(p, i, j): if m[i][j] >= 0: return m[i][j] if i == j: m[i][j] = 0 else: for k in range(i,j) q = LookupMatrixChain(p,i,k) +\ LookupMatrixChain(p,k+1,j) + p[i-1]*p[k]*p[j] if (q <= m[i][j]): m[i][j] = q return m[i][j]

  21. Inne klasyczne zastosowania programowania dynamicznego • Najdłuższy wspólny podciąg; • Triangulacja wielokąta z minimalną długością boków.

  22. Algorytmy zachłanne • Algorytm jest rozumiany jako ciąg decyzji optymalizacyjnych; • W kolejnym kroku wybierane jest najlepsze dostępne lokalnie rozwiązanie; • Niestety nie zawsze ta strategia prowadzi do optymalnych rozwiązań całościowych.

  23. Problem plecakowy - ciągły Sformułowanie: Dla danego zbioru przedmiotów (opisanych przez wagę i cenę) i plecaka o rozmiarze K znaleźć upakowanie plecaka o największej wartości. Dysponujemy ograniczoną ilością przedmiotów każdego rodzaju. Przedmioty MOŻNA dzielić. Tj. dla Z = { (c1,w1,m1), (c2,w2,m2), (c3,w3,m3) … (cn,wn,mn) } znaleźć podzbiór L = (l1, l2, ..., ln), taki że å li*wi£ K, liÎ R+, li£ mi i å li*ci = max

  24. Problem plecakowy - ciągły Przykład (bez limitów): Przedmioty: Z = { (3, 1), (60, 10), (80, 15), (210, 30), (270, 45) } Plecak: K = 45 Optymalne upakowanie: KN(K, Z) = 315 Liczby przedmiotów: L = (0, 0, 0, 1.5, 0)

  25. Problem plecakowy - ciągły Przykład (z limitami): Przedmioty: Z = { (3, 1), (60, 10), (80, 15), (210, 30), (270, 45) } Plecak: K = 45 Optymalne upakowanie: KN(K, Z) = 300 Liczby przedmiotów: L = (0, 0, 0, 1, 1/3) lub (0, 1, 0, 1, 1/9)

  26. Ciągły problem plecakowy – algorytm // nielimitowana ilość przedmiotów deef Knapsack (goods, KSize): # przedmiot o najlepszym stosunku ceny do wagi i = GetMaxPrizeToValue(goods, n) KValue = KSize / goods[i].weight * goods[i].price return KValue

  27. Ciągły problem plecakowy – algorytm Knapsack (goods, KSize) KValue = 0cnt=0 while K >= 0 : # najlepszy stosunek ceny do wagi i max > 0 i = GetMaxPrizeToValue(goods, n) if KSize< goods[i].weight * goods[i].max: cnt = KSize / goods[i].weight else: Z[i].maxKSize = KSize - cnt KValue += KValue + cnt* goods[i].price goods[i].max = 0 return KValue

  28. Inne klasyczne zastosowania algorytmów zachłannych • Przydział jak największej ilości zajęć do zasobu (przy założeniu wzajemnego wykluczania); • Drzewo spinające w grafie. • Własność zachłannego wyboru; • Matroidy.

  29. Kodowanie Huffmana • Kodowanie o stałej długości – kody wszystkich znaków są jednakowe, np.: A = 01000001, B = 01000010, C = 01000011, … • Kodowanie o zmiennej długości – kody znaków mają różne długości (im rzadszy znak, tym większa długość kodu) • Kod prefixowy (kod dowolnego znaku nie jest prefixem innego)

  30. 2 2 1 1 1 1 3 2 2 1 1 1 1 1 Kodowanie Huffmana (1952) W kolejnym kroku scalane są dwa drzewa o najmniejszej wadze. NIE PIEPRZ PIETRZE WIEPRZA PIEPRZEM I II Częstotliwości: A W N: 1 T N T: 1 W: 1 A: 1 III M: 1 R: 4 Z: 4 : 4 I: 6 M P: 6 A W E: 7 T N

  31. drzewo N: 101110 1 35 T: 101111 0 W: 10100 15 20 A: 10101 M: 10110 7 8 9 11 R: 010 E Z: 011 : 100 4 4 4 5 5 6 R Z  I P I: 110 P: 111 2 3 E: 00 1 1 1 2 normalnie: 35 x 8 = 280 b po kompresji: 110 bitów średnio: 3, 14 bity na znak W A M 1 1 T N Kodowanie Huffmana (1952) NIE PIEPRZ PIETRZE WIEPRZA PIEPRZEM

More Related