Lo que vas a aprender
- Cuándo se puede aplicar programación dinámica.
- La diferencia entre memoización y tabulación.
- Cómo plantear el estado y la recurrencia de un problema.
- Cómo reconstruir la solución, no solo su valor.
- Los problemas clásicos: monedas, mochila, subsecuencia común y distancia de edición.
Fundamentos teóricos
Cuándo se aplica
Un problema se presta a programación dinámica si tiene:- Subestructura óptima: la solución óptima se construye a partir de soluciones óptimas de subproblemas.
- Subproblemas solapados: los mismos subproblemas aparecen muchas veces.
Ejemplo: Fibonacci
. La recursión directa recalcula lo mismo muchísimas veces: hace unos llamadas. Guardando los resultados, solo hay 51 subproblemas distintos.Memoización (de arriba abajo)
Se escribe la recursión normal y se guarda cada resultado en una tabla:Tabulación (de abajo arriba)
Se rellena la tabla empezando por los casos más pequeños, sin recursión:Cómo plantear un problema
- Estado: ¿qué parámetros definen un subproblema? Por ejemplo, : el mejor valor con los primeros objetos y capacidad .
- Recurrencia: ¿cómo se obtiene un estado a partir de otros más pequeños?
- Casos base.
- Orden de cálculo: que cada estado se calcule después de aquellos de los que depende.
- Respuesta: ¿qué estado contiene la solución?
Problemas clásicos
Ejemplos resueltos
Ejemplo 1 · Cambio de monedas
Ejemplo 1 · Cambio de monedas
Mínimo de monedas para pagar 11 con monedas de 1, 5 y 6.El algoritmo voraz (coger siempre la moneda más grande) daría 6 + 1 + 1 + 1 + 1 + 1 = 6 monedas.
Ejemplo 2 · Mochila 0/1
Ejemplo 2 · Mochila 0/1
Capacidad 7; objetos (peso, valor): (1, 1), (3, 4), (4, 5), (5, 7).La mejor opción es llevar los objetos de peso 3 y 4 (valor 9). Recorrer hacia atrás permite usar una sola fila.
Ejemplo 3 · Subsecuencia común más larga
Ejemplo 3 · Subsecuencia común más larga
Entre Es lo que usa
"ABCBDAB" y "BDCABA":diff para comparar ficheros, y se usa también para alinear secuencias de ADN.Ejemplo 4 · Distancia de edición (Levenshtein)
Ejemplo 4 · Distancia de edición (Levenshtein)
Mínimo de inserciones, borrados y sustituciones para pasar de Es la base de los correctores ortográficos.
"gato" a "pato": 1. De "casa" a "calle": 3.Ejemplo 5 · Reconstruir la solución
Ejemplo 5 · Reconstruir la solución
Para saber qué objetos van en la mochila, se guarda la tabla completa y se recorre hacia atrás: si , el objeto está dentro y se pasa a .
Errores frecuentes
- No identificar bien el estado. Si falta información en el estado, la recurrencia no es correcta.
- Calcular estados en un orden equivocado en la tabulación, usando valores aún no calculados.
- En la mochila 0/1 con una fila, recorrer hacia delante: cada objeto se usaría varias veces (eso es la mochila ilimitada).
- Aplicar un algoritmo voraz donde no funciona, como el cambio de monedas con valores arbitrarios.
- Usar memoización con mucha profundidad en lenguajes con pila limitada.
Preguntas frecuentes
¿Por qué se llama 'dinámica'?
¿Por qué se llama 'dinámica'?
Richard Bellman eligió el nombre en los años 50, según contó, porque sonaba bien y ocultaba que hacía investigación matemática a un secretario de Defensa que la detestaba. “Programación” significaba planificar, no escribir código.
¿Dónde se usa en la práctica?
¿Dónde se usa en la práctica?
En el GPS y los mapas (caminos mínimos), en la bioinformática (alineamiento de secuencias), en el reconocimiento de voz (algoritmo de Viterbi), en el control óptimo, en los compiladores y en finanzas (valoración de opciones).
Temas relacionados
Recursión en C
La pila de llamadas paso a paso.
Divide y vencerás
Cuando los subproblemas no se repiten.
Notación asintótica
Medir el coste de los algoritmos.