Co to jest programowanie dynamiczne ?
Czym różni się od rekurencji, zapamiętywania itp.?
Przeczytałem o nim artykuł w Wikipedii , ale nadal go nie rozumiem.
algorithm
dynamic-programming
smac89
źródło
źródło
Odpowiedzi:
Programowanie dynamiczne polega na wykorzystaniu wiedzy z przeszłości w celu ułatwienia rozwiązania przyszłego problemu.
Dobrym przykładem jest rozwiązanie sekwencji Fibonacciego dla n = 1.000,002.
To będzie bardzo długi proces, ale co, jeśli dam ci wyniki dla n = 1 000 000 in = 1 000,001? Nagle problem stał się łatwiejszy do opanowania.
Programowanie dynamiczne jest często stosowane w problemach z łańcuchem, takich jak problem z edycją łańcucha. Rozwiązujesz podzbiory problemu, a następnie wykorzystujesz te informacje do rozwiązania trudniejszego problemu oryginalnego.
Dzięki programowaniu dynamicznemu przechowujesz swoje wyniki w jakiejś tabeli. Gdy potrzebujesz odpowiedzi na problem, odnieś się do tabeli i sprawdź, czy już wiesz, co to jest. Jeśli nie, wykorzystasz dane z tabeli, aby dać sobie krok w kierunku odpowiedzi.
Książka Cormen Algorytmy ma świetny rozdział o programowaniu dynamicznym. I to jest bezpłatne w Google Books! Sprawdź to tutaj.
źródło
Programowanie dynamiczne jest techniką stosowaną w celu uniknięcia wielokrotnego obliczania tego samego podproblemu w algorytmie rekurencyjnym.
Weźmy prosty przykład liczb Fibonacciego: znalezienie n- tej liczby Fibonacciego zdefiniowanej przez
F n = F n-1 + F n-2 i F 0 = 0, F 1 = 1
Rekurencja
Oczywistym sposobem na to jest rekurencja:
Programowanie dynamiczne
Rekurencja wykonuje wiele niepotrzebnych obliczeń, ponieważ dana liczba Fibonacciego zostanie obliczona wiele razy. Prostym sposobem na poprawę tego jest buforowanie wyników:
Lepszym sposobem na to jest całkowite pozbycie się rekurencji poprzez ocenę wyników we właściwej kolejności:
Możemy nawet użyć stałej przestrzeni i po drodze przechowywać tylko niezbędne częściowe wyniki:
Jak zastosować programowanie dynamiczne?
Programowanie dynamiczne zasadniczo działa w przypadku problemów, które mają naturalną kolejność od lewej do prawej, takich jak ciągi znaków, drzewa lub sekwencje liczb całkowitych. Jeśli naiwny algorytm rekurencyjny nie oblicza wielokrotnie tego samego podproblemu, programowanie dynamiczne nie pomoże.
Zrobiłem zbiór problemów, aby pomóc zrozumieć logikę: https://github.com/tristanguigue/dynamic-programing
źródło
if n in cache
jak w przykładzie z góry na dół, czy czegoś mi brakuje?Zapamiętywanie to zapisywanie poprzednich wyników wywołania funkcji (rzeczywista funkcja zawsze zwraca to samo, biorąc pod uwagę te same dane wejściowe). Nie ma to znaczenia dla złożoności algorytmu przed zapisaniem wyników.
Rekurencja jest metodą wywoływaną przez funkcję, zwykle z mniejszym zestawem danych. Ponieważ większość funkcji rekurencyjnych można przekształcić w podobne funkcje iteracyjne, nie ma to również znaczenia dla złożoności algorytmicznej.
Programowanie dynamiczne to proces rozwiązywania łatwiejszych do rozwiązania pod-problemów i budowania na ich podstawie odpowiedzi. Większość algorytmów DP będzie działać w czasie między algorytmem chciwym (jeśli taki istnieje) a algorytmem wykładniczym (wylicz wszystkie możliwości i znajdź najlepszy).
źródło
Jest to optymalizacja algorytmu, która skraca czas działania.
Podczas gdy Chciwy Algorytm jest zwykle nazywany naiwnym , ponieważ może działać wiele razy na tym samym zestawie danych, Programowanie dynamiczne pozwala uniknąć tej pułapki poprzez głębsze zrozumienie częściowych wyników, które muszą być przechowywane, aby pomóc w zbudowaniu ostatecznego rozwiązania.
Prostym przykładem jest przemierzanie drzewa lub wykresu tylko przez węzły, które przyczyniłyby się do rozwiązania, lub umieszczenie w tabeli rozwiązań, które do tej pory znalazłeś, aby uniknąć wielokrotnego przemierzania tych samych węzłów.
Oto przykład problemu, który nadaje się do programowania dynamicznego, autorstwa internetowego sędzia UVA: Edit Steps Ladder.
Zrobię krótkie omówienie ważnej części analizy tego problemu, zaczerpniętej z książki Wyzwania programistyczne, sugeruję, aby to sprawdzić.
Tutaj bardzo szczególna analiza tego, co jest potrzebne do zebrania najbardziej optymalnych wyników cząstkowych, sprawia, że rozwiązanie jest „dynamiczne”.
Oto alternatywne, pełne rozwiązanie tego samego problemu. Jest to również „dynamiczny”, mimo że jego wykonanie jest inne. Sugeruję sprawdzenie skuteczności rozwiązania, przekazując go internetowemu sędziemu UVA. Wydaje mi się niesamowite, jak tak skutecznie rozwiązano tak poważny problem.
źródło
Kluczowymi częściami programowania dynamicznego są „nakładające się podproblemy” i „optymalna podbudowa”. Te właściwości problemu oznaczają, że optymalne rozwiązanie składa się z optymalnych rozwiązań jego podproblemów. Na przykład problemy z najkrótszą ścieżką wykazują optymalną strukturę. Najkrótsza ścieżka od A do C to najkrótsza ścieżka od A do jakiegoś węzła B, po której następuje najkrótsza ścieżka od tego węzła B do C.
Bardziej szczegółowo, aby rozwiązać problem najkrótszej ścieżki:
Ponieważ pracujemy oddolnie, mamy już rozwiązania podproblemów, kiedy przychodzi czas na ich użycie, poprzez ich zapamiętanie.
Pamiętaj, że problemy z programowaniem dynamicznym muszą mieć zarówno nakładające się podproblemy, jak i optymalną podbudowę. Generowanie sekwencji Fibonacciego nie stanowi problemu z programowaniem dynamicznym; korzysta z zapamiętywania, ponieważ ma nakładające się podproblemy, ale nie ma optymalnej podbudowy (ponieważ nie wiąże się z tym problem optymalizacji).
źródło
Programowanie dynamiczne
Definicja
Programowanie dynamiczne (DP) to ogólna technika projektowania algorytmów służąca do rozwiązywania problemów z nakładającymi się podproblemami. Technikę tę wynalazł amerykański matematyk „Richard Bellman” w latach 50. XX wieku.
Kluczowy pomysł
Kluczową ideą jest zapisanie odpowiedzi nakładających się mniejszych podproblemów, aby uniknąć ponownego obliczenia.
Dynamiczne właściwości programowania
źródło
Jestem również bardzo nowy w programowaniu dynamicznym (potężny algorytm dla określonego rodzaju problemów)
Mówiąc najprościej, wystarczy pomyśleć o programowaniu dynamicznym jako podejściu rekurencyjnym z wykorzystaniem wcześniejszej wiedzy
Najważniejsza jest wcześniejsza wiedza. Śledź rozwiązania już istniejących problemów.
Rozważ ten najbardziej podstawowy przykład dp z Wikipedii
Znalezienie sekwencji Fibonacciego
Przełammy wywołanie funkcji, powiedzmy n = 5
W szczególności Fib (2) obliczono trzy razy od zera. W większych przykładach oblicza się znacznie więcej wartości Fib lub podproblemów, co prowadzi do wykładniczego algorytmu czasu.
Teraz wypróbujmy to, przechowując wartość, którą już znaleźliśmy w strukturze danych, na przykład mapę
Tutaj zapisujemy rozwiązanie podproblemów na mapie, jeśli jeszcze go nie mamy. Ta technika zapisywania wartości, które już obliczyliśmy, jest nazywana Zapamiętywaniem.
Wreszcie, w przypadku problemu, najpierw spróbuj znaleźć stany (możliwe podproblemy i spróbuj wymyślić lepsze podejście rekurencyjne, abyś mógł zastosować rozwiązanie poprzedniego podproblemu do kolejnych).
źródło
Programowanie dynamiczne to technika rozwiązywania problemów z nakładającymi się problemami podrzędnymi. Algorytm programowania dynamicznego rozwiązuje każdy problem podrzędny tylko raz, a następnie zapisuje swoją odpowiedź w tabeli (tablicy). Unikanie pracy ponownego obliczania odpowiedzi za każdym razem, gdy napotyka się problem podrzędny. Podstawową ideą programowania dynamicznego jest: Unikaj dwukrotnego obliczania tych samych rzeczy, zwykle poprzez utrzymywanie tabeli znanych wyników podproblemów.
Siedem kroków w rozwoju algorytmu programowania dynamicznego jest następujące:
źródło
6. Convert the memoized recursive algorithm into iterative algorithm
to obowiązkowy krok? Oznaczałoby to, że jego ostateczna forma nie jest rekurencyjna?w skrócie różnica między zapamiętywaniem rekurencyjnym a programowaniem dynamicznym
Programowanie dynamiczne, jak sugeruje nazwa, wykorzystuje poprzednią obliczoną wartość do dynamicznego konstruowania następnego nowego rozwiązania
Gdzie zastosować programowanie dynamiczne: Jeśli twoje rozwiązanie opiera się na optymalnej podbudowie i pokrywającym się podproblemie, wówczas w takim przypadku przydatne będzie użycie wcześniej obliczonej wartości, więc nie musisz jej ponownie obliczać. To podejście oddolne. Załóżmy, że musisz obliczyć Fib (n). W takim przypadku wystarczy dodać poprzednią obliczoną wartość Fib (n-1) i Fib (n-2)
Rekurencja: Zasadniczo dzielenie problemu na mniejsze części w celu jego łatwego rozwiązania, ale należy pamiętać, że nie uniknie się ponownego obliczenia, jeśli mamy taką samą wartość obliczoną wcześniej w innym wywołaniu rekurencyjnym.
Zapamiętywanie: Zasadniczo zapisywanie starej obliczonej wartości rekurencji w tabeli jest znane jako zapamiętywanie, które pozwoli uniknąć ponownego obliczenia, jeśli zostało już obliczone przez jakieś poprzednie wywołanie, więc dowolna wartość zostanie obliczona raz. Dlatego przed obliczeniem sprawdzamy, czy ta wartość została już obliczona, czy nie, jeśli już została obliczona, a następnie zwracamy to samo z tabeli zamiast ponownego obliczania. Jest to również podejście odgórne
źródło
Oto przykład prostego kodu Pythona z
Recursive
,Top-down
,Bottom-up
podejście do serii Fibonacciego:Rekurencyjny: O (2 n )
Z góry na dół: O (n) Wydajny przy większych wejściach
Z dołu do góry: O (n) Dla uproszczenia i małych rozmiarów wejściowych
źródło