W tym samouczku dowiesz się, czym jest programowanie dynamiczne. Znajdziesz również porównanie między programowaniem dynamicznym a zachłannymi algorytmami do rozwiązywania problemów.
Programowanie dynamiczne to technika w programowaniu komputerowym, która pomaga efektywnie rozwiązywać klasę problemów, które mają nakładające się podproblemy i optymalną własność podstruktury.
Takie problemy wymagają wielokrotnego obliczania wartości tych samych podproblemów w celu znalezienia optymalnego rozwiązania.
Przykład programowania dynamicznego
Weźmy przypadek generowania sekwencji Fibonacciego.
Jeśli sekwencja to F (1) F (2) F (3)… F (50), jest zgodna z regułą F (n) = F (n-1) + F (n-2)
F (50) = F (49) + F (48) F (49) = F (48) + F (47) F (48) = F (47) + F (46)…
Zauważ, że istnieją nakładające się podproblemy, musimy obliczyć F (48), aby obliczyć zarówno F (50), jak i F (49). To jest dokładnie ten rodzaj algorytmu, w którym świeci programowanie dynamiczne.
Jak działa programowanie dynamiczne
Programowanie dynamiczne działa na zasadzie przechowywania wyników podproblemów tak, że gdy ich rozwiązania są potrzebne, są pod ręką i nie musimy ich ponownie przeliczać.
Ta technika przechowywania wartości podproblemów nazywana jest zapamiętywaniem. Zapisując wartości w tablicy, oszczędzamy czas na obliczenia podproblemów, z którymi już się spotkaliśmy.
var m = map (0 → 0, 1 → 1) function fib (n) jeśli klucza n nie ma na mapie mm (n) = fib (n - 1) + fib (n - 2) return m (n)
Programowanie dynamiczne przez zapamiętywanie jest podejściem odgórnym do programowania dynamicznego. Odwracając kierunek działania algorytmu, tj. Wychodząc od przypadku podstawowego i pracując w kierunku rozwiązania, możemy również zaimplementować programowanie dynamiczne w sposób oddolny.
funkcja fib (n) if n = 0 return 0 else var prevFib = 0, currFib = 1 powtórz n - 1 razy var newFib = prevFib + currFib prevFib = currFib currFib = newFib zwraca currentFib
Programowanie rekurencyjne a programowanie dynamiczne
Programowanie dynamiczne jest głównie stosowane w algorytmach rekurencyjnych. Nie jest to przypadek, większość problemów związanych z optymalizacją wymaga rekursji, a do optymalizacji używa się programowania dynamicznego.
Ale nie wszystkie problemy wykorzystujące rekursję mogą korzystać z programowania dynamicznego. O ile nie występują nakładające się podproblemy, jak w przypadku problemu sekwencji Fibonacciego, rekurencja może osiągnąć rozwiązanie tylko przy użyciu metody dziel i zwyciężaj.
To jest powód, dla którego algorytm rekurencyjny, taki jak sortowanie przez scalanie, nie może korzystać z programowania dynamicznego, ponieważ podproblemy nie nakładają się w żaden sposób.
Chciwe algorytmy a programowanie dynamiczne
Algorytmy Greedy są podobne do programowania dynamicznego w tym sensie, że oba są narzędziami optymalizacji.
Jednak zachłanne algorytmy szukają lokalnie optymalnych rozwiązań lub innymi słowy chciwego wyboru, w nadziei na znalezienie optymalnego globalnego. Dlatego chciwe algorytmy mogą odgadnąć, że wygląda to optymalnie w danym momencie, ale staje się kosztowne i nie gwarantuje globalnego optimum.
Z drugiej strony programowanie dynamiczne znajduje optymalne rozwiązanie dla podproblemów, a następnie dokonuje świadomego wyboru połączenia wyników tych podproblemów w celu znalezienia najbardziej optymalnego rozwiązania.