¿Qué es la programación dinámica ?
¿En qué se diferencia de recursividad, memorización, etc.?
He leído el artículo de Wikipedia en él, pero todavía no lo entiendo.
algorithm
dynamic-programming
smac89
fuente
fuente
Respuestas:
La programación dinámica es cuando utiliza el conocimiento pasado para facilitar la resolución de un problema futuro.
Un buen ejemplo es resolver la secuencia de Fibonacci para n = 1,000,002.
Este será un proceso muy largo, pero ¿qué pasa si le doy los resultados para n = 1,000,000 yn = 1,000,001? De repente, el problema se volvió más manejable.
La programación dinámica se usa mucho en problemas de cadenas, como el problema de edición de cadenas. Usted resuelve un subconjunto (s) del problema y luego usa esa información para resolver el problema original más difícil.
Con la programación dinámica, generalmente almacena sus resultados en algún tipo de tabla. Cuando necesite la respuesta a un problema, haga referencia a la tabla y vea si ya sabe cuál es. Si no, usa los datos en su tabla para darse un paso hacia la respuesta.
El libro de Algoritmos de Cormen tiene un gran capítulo sobre programación dinámica. ¡Y es gratis en Google Books! Compruébalo aquí.
fuente
La programación dinámica es una técnica utilizada para evitar calcular varias veces el mismo subproblema en un algoritmo recursivo.
Tomemos el ejemplo simple de los números de Fibonacci: encontrar el n º número de Fibonacci definida por
F n = F n-1 + F n-2 y F 0 = 0, F 1 = 1
Recursividad
La forma obvia de hacer esto es recursiva:
Programación dinámica
La recursión hace muchos cálculos innecesarios porque un número de Fibonacci determinado se calculará varias veces. Una manera fácil de mejorar esto es almacenar en caché los resultados:
Una mejor manera de hacer esto es deshacerse de la recursión al evaluar los resultados en el orden correcto:
Incluso podemos usar espacio constante y almacenar solo los resultados parciales necesarios en el camino:
¿Cómo aplicar la programación dinámica?
La programación dinámica generalmente funciona para problemas que tienen un orden inherente de izquierda a derecha, como cadenas, árboles o secuencias de enteros. Si el ingenuo algoritmo recursivo no calcula el mismo subproblema varias veces, la programación dinámica no ayudará.
Hice una colección de problemas para ayudar a entender la lógica: https://github.com/tristanguigue/dynamic-programing
fuente
if n in cache
como con el ejemplo de arriba hacia abajo o me falta algo?La memorización es cuando almacena resultados previos de una llamada a función (una función real siempre devuelve lo mismo, dadas las mismas entradas). No hace una diferencia para la complejidad algorítmica antes de que se almacenen los resultados.
La recursión es el método de una función que se llama a sí misma, generalmente con un conjunto de datos más pequeño. Dado que la mayoría de las funciones recursivas se pueden convertir en funciones iterativas similares, esto tampoco hace una diferencia para la complejidad algorítmica.
La programación dinámica es el proceso de resolver subproblemas más fáciles de resolver y construir la respuesta a partir de eso. La mayoría de los algoritmos DP estarán en el tiempo de ejecución entre un algoritmo Greedy (si existe) y un algoritmo exponencial (enumere todas las posibilidades y encuentre el mejor).
fuente
Es una optimización de su algoritmo que reduce el tiempo de ejecución.
Si bien un algoritmo codicioso generalmente se llama ingenuo , ya que puede ejecutarse varias veces sobre el mismo conjunto de datos, la programación dinámica evita esta trampa a través de una comprensión más profunda de los resultados parciales que deben almacenarse para ayudar a construir la solución final.
Un ejemplo simple es atravesar un árbol o un gráfico solo a través de los nodos que contribuirían con la solución, o poner en una tabla las soluciones que has encontrado hasta ahora para que puedas evitar atravesar los mismos nodos una y otra vez.
Aquí hay un ejemplo de un problema adecuado para la programación dinámica, del juez en línea de UVA: Edit Steps Ladder.
Voy a hacer un breve resumen de la parte importante del análisis de este problema, tomado del libro Desafíos de programación, le sugiero que lo revise.
Aquí, un análisis muy particular de lo que se necesita para obtener los resultados parciales más óptimos es lo que hace que la solución sea "dinámica".
Aquí hay una solución alternativa completa para el mismo problema. También es "dinámico" a pesar de que su ejecución es diferente. Le sugiero que compruebe cuán eficiente es la solución enviándola al juez en línea de UVA. Me parece sorprendente cómo se abordó un problema tan pesado de manera tan eficiente.
fuente
Los bits clave de la programación dinámica son "subproblemas superpuestos" y "subestructura óptima". Estas propiedades de un problema significan que una solución óptima se compone de las soluciones óptimas para sus subproblemas. Por ejemplo, los problemas de la ruta más corta exhiben una subestructura óptima. La ruta más corta de A a C es la ruta más corta de A a algún nodo B seguido de la ruta más corta de ese nodo B a C.
En mayor detalle, para resolver un problema de ruta más corta:
Debido a que estamos trabajando de abajo hacia arriba, ya tenemos soluciones a los subproblemas a la hora de usarlos, memorizándolos.
Recuerde, los problemas de programación dinámica deben tener subproblemas superpuestos y una subestructura óptima. Generar la secuencia de Fibonacci no es un problema de programación dinámica; utiliza la memorización porque tiene subproblemas superpuestos, pero no tiene una subestructura óptima (porque no hay ningún problema de optimización involucrado).
fuente
Programación dinámica
Definición
La programación dinámica (DP) es una técnica general de diseño de algoritmos para resolver problemas con subproblemas superpuestos. Esta técnica fue inventada por el matemático estadounidense "Richard Bellman" en la década de 1950.
Idea clave
La idea clave es guardar las respuestas de subproblemas superpuestos más pequeños para evitar el recálculo.
Propiedades de programación dinámica
fuente
También soy muy nuevo en la programación dinámica (un algoritmo poderoso para un tipo particular de problemas)
En palabras más simples, solo piense en la programación dinámica como un enfoque recursivo con el uso del conocimiento previo
El conocimiento previo es lo que más importa aquí. Haga un seguimiento de la solución de los subproblemas que ya tiene.
Considere esto, el ejemplo más básico para dp de Wikipedia
Encontrar la secuencia de fibonacci
Analicemos la llamada a la función con say n = 5
En particular, fib (2) se calculó tres veces desde cero. En ejemplos más grandes, se recalculan muchos más valores de fib o subproblemas, lo que lleva a un algoritmo de tiempo exponencial.
Ahora, intentemos almacenando el valor que ya descubrimos en una estructura de datos, digamos un Mapa
Aquí estamos guardando la solución de subproblemas en el mapa, si aún no la tenemos. Esta técnica de guardar valores que ya habíamos calculado se denomina Memoization.
Por último, para un problema, primero intente encontrar los estados (posibles subproblemas e intente pensar en el mejor enfoque de recursión para que pueda usar la solución del subproblema anterior en otros).
fuente
La programación dinámica es una técnica para resolver problemas con problemas secundarios superpuestos. Un algoritmo de programación dinámica resuelve cada subproblema solo una vez y luego guarda su respuesta en una tabla (matriz). Evitar el trabajo de volver a calcular la respuesta cada vez que se encuentra el subproblema. La idea subyacente de la programación dinámica es: Evite calcular las mismas cosas dos veces, generalmente manteniendo una tabla de resultados conocidos de subproblemas.
Los siete pasos en el desarrollo de un algoritmo de programación dinámica son los siguientes:
fuente
6. Convert the memoized recursive algorithm into iterative algorithm
un paso obligatorio? ¿Esto significaría que su forma final no es recursiva?en resumen, la diferencia entre la memoria de recursión y la programación dinámica
La programación dinámica como sugiere su nombre es utilizar el valor calculado anterior para construir dinámicamente la próxima solución nueva
Dónde aplicar la programación dinámica: si su solución se basa en una subestructura óptima y un subproceso superpuesto, en ese caso será útil usar el valor calculado anterior para que no tenga que volver a calcularlo. Es un enfoque de abajo hacia arriba. Suponga que necesita calcular fib (n) en ese caso, todo lo que necesita hacer es agregar el valor calculado anterior de fib (n-1) y fib (n-2)
Recursión: Básicamente subdividiendo su problema en una parte más pequeña para resolverlo con facilidad, pero tenga en cuenta que no evita el recálculo si tenemos el mismo valor calculado previamente en otra llamada de recursión.
Memorización: Básicamente, el almacenamiento del antiguo valor de recursión calculado en la tabla se conoce como memorización, lo que evitará el recálculo si ya ha sido calculado por alguna llamada anterior, por lo que cualquier valor se calculará una vez. Entonces, antes de calcular, verificamos si este valor ya se calculó o no, si ya se calculó, luego devolvemos lo mismo de la tabla en lugar de volver a calcular. También es un enfoque de arriba hacia abajo
fuente
Aquí está un ejemplo sencillo de código Python
Recursive
,Top-down
,Bottom-up
enfoque para la serie de Fibonacci:Recursivo: O (2 n )
De arriba hacia abajo: O (n) Eficiente para entradas más grandes
De abajo hacia arriba: O (n) Para simplicidad y pequeños tamaños de entrada
fuente