La programación dinámica es una técnica de diseño de algoritmos que busca mejorar la complejidad en tiempo de la solución de un problema que se pueda plantear desde una filosofía recursiva, empleando la reutilización de las soluciones ya obtenidas con una estructura de datos auxiliar, cuyos elementos representan sub-problemas específicos (según cómo se determine). Puede ser top-down (desde lo más general hacia abajo, requiere un manejo recursivo empleando “memoization”), o bien bottom-up (iterativo, partiendo del problema trivial hasta el problema más general)
El procedimiento que se sigue para plantear la solución de programación dinámica a un problema es el siguiente:
1. Identificar los problemas triviales del problema, a partir de los cuales se puedan generalizar luego problemas más complejos
2. Verificar cuáles problemaas están apenas un nivel más alto que el trivial, e inducir una generalización recursiva (y de optimización, si es el caso) para éstos
3. Determinar finalmente la respuesta de los problemas generalizados a partir de la estructura de datos que contiene las soluciones calculadas
En problemas de optimización, la estructura de datos de apoyo almacena las soluciones óptimas a los problemas de decisión (de los problemas triviales a los más generales); de este modo, para establecer la solución general hay que basarse en las decisiones de optimización que quedan reflejadas en dicha estructura (recorriendo desde los problemas triviales hasta el más general, tomando nota de los elementos a los que corresponden los valores óptimos, información que es proporcionada por los índices de las casillas a los que corresponden los problemas particulares)
-
Ejemplo 1: Factorial
Primero se identifican los problemas triviales:
factorial de 0 = 1 factorial de 1 = 1
Luego se induce una generalización partiendo de problemas apenas mayores a los triviales:
factorial de 2 = 2 * factorial de 1 factorial de 3 = 3 * factorial de 2 ... factorial de N = N * factorial de N-1
Se define la estructura solución:
solucion[i] = factorial de i
El algoritmo queda:
funcion factorial(N : entero) : entero soluciones <- Nuevo arreglo de enteros tamaño N solucion[0] <- 0 // Solucion trivial solucion[1] <- 1 // Solucion trivial para i <- 2 hasta N solucion[i] <- i * solucion[i-1] // Solucion general retorna solucion[N] // Solucion final
-
Ejemplo 2: Elemento de la secuencia de Fibonacci
Problemas triviales:
Fibonacci de 0 = 1 Fibonacci de 1 = 1
Generalización:
Fibonacci de 2 = Fibonacci de 1 + Fibonacci de 0 Fibonacci de 3 = Fibonacci de 2 + Fibonacci de 1 ... Fibonacci de N = Fibonacci de N-1 + Fibonacci de N-2
Se define la estructura solución:
solucion[i] = Fibonacci de i
Algoritmo:
funcion fibonacci(N : entero) : entero solucion <- Nuevo arreglo de tamaño N solucion[0] <- 1 solucion[1] <- 1 para i <-2 hasta N solucion[i] <- solucion[i-1] + solucion[i-2] return solucion[N]
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?