Successfully reported this slideshow.

Programación Dinámica

73,135 views

Published on

Descripción del esquema algorítmico de programación dinámica con un par de ejemplos aclaratorios

Published in: Technology

Programación Dinámica

  1. 1. Programación dinámica <ul><li>Método general. </li></ul><ul><li>Análisis de tiempos de ejecución. </li></ul><ul><li>Ejemplos de aplicación. </li></ul><ul><li> 3.1. Problema del cambio de monedas. </li></ul><ul><li> 3.2. Problema de la mochila 0/1. </li></ul>
  2. 2. Método general <ul><li>La programación dinámica se suele utilizar en problemas de optimización , donde una solución está formada por una serie de decisiones. </li></ul><ul><li>Igual que la técnica divide y vencerás , resuelve el problema original combinando las soluciones para subproblemas más pequeños. </li></ul><ul><li>Sin embargo, la programación dinámica no utiliza recursividad, sino que almacena los resultados de los subproblemas en una tabla , calculando primero las soluciones para los problemas pequeños. </li></ul><ul><li>Con esto se pretende evitar la repetición de cálculos para problemas más pequeños. </li></ul>
  3. 3. Método general <ul><li>Ejemplo. Cálculo de los números de Fibonacci. </li></ul><ul><li>Con método recursivo </li></ul><ul><ul><li>Fibonacci (n: integer) </li></ul></ul><ul><ul><li> Si n<2 Devolver 1 </li></ul></ul><ul><ul><li> Sino Devolver Fibonacci (n-1) + Fibonacci (n-2) </li></ul></ul><ul><ul><li>Problema: Muchos cálculos están repetidos, tiempo de ejec. exponencial. </li></ul></ul><ul><ul><li>Solución: Calcular los valores de menor a mayor empezando por 0, e ir guardando los resultados en una tabla. </li></ul></ul><ul><li>Con programación dinámica </li></ul><ul><ul><ul><ul><li>Fibonacci (n: integer) </li></ul></ul></ul></ul><ul><ul><ul><ul><li> T[0] = 0; T[1] = 1 </li></ul></ul></ul></ul><ul><ul><ul><ul><li> para i = 2,3, ...,n </li></ul></ul></ul></ul><ul><ul><ul><ul><li> T[i] = T[i-1] + T[i-2] </li></ul></ul></ul></ul><ul><ul><ul><ul><li> Devolver T[n] </li></ul></ul></ul></ul><ul><ul><li>Se utiliza la misma fórmula que en la versión anterior, pero de forma más inteligente. El tiempo de ejecución es  (n). </li></ul></ul>
  4. 4. Método general <ul><li>Los algoritmos divide y vencerás están dentro de los métodos descendentes . </li></ul><ul><ul><li>Empezar con el problema original y descomponer en pasos sucesivos en problemas de menor tamaño. </li></ul></ul><ul><ul><li>Partiendo del problema grande, descendemos hacia problemas más sencillos. </li></ul></ul><ul><li>La programación dinámica , por el contrario, es un método ascendente : </li></ul><ul><ul><li>Resolvemos primero los problemas pequeños (guardando las soluciones en una tabla) y después vamos combinando para resolver los problemas más grandes. </li></ul></ul>
  5. 5. Método general <ul><li>La programación dinámica se basa en el Principio de Optimalidad de Bellman : cualquier subsecuencia de una secuencia óptima debe ser, a su vez, una secuencia óptima. </li></ul><ul><li>Para cada problema deberíamos comprobar si es aplicable el principio de optimalidad. </li></ul><ul><li>Ejemplo . </li></ul><ul><ul><ul><ul><ul><li>2 B 9 </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><li>A D </li></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>3 C 7 </li></ul></ul></ul></ul></ul><ul><li>Camino óptimo de A a D: A-C-D, de longitud 10 </li></ul><ul><li>Camino óptimo de A al siguiente nivel: A-B, de longitud 2, y después B-D de longitud 9. Total: A-B-D, de longitud 11 </li></ul><ul><li>¿Cumple el Principio de Optimalidad? </li></ul>
  6. 6. Método general <ul><li>Aspectos a definir en un algoritmo de programación dinámica: </li></ul><ul><ul><li>Ecuación recurrente , para calcular la solución de los problemas grandes en función de los problemas más pequeños. </li></ul></ul><ul><ul><li>Determinar los casos base . </li></ul></ul><ul><ul><li>Definir las tablas utilizadas por el algoritmo, y cómo son rellenadas. </li></ul></ul><ul><ul><li>Cómo se recompone la solución global a partir de los valores de las tablas. </li></ul></ul>
  7. 7. Análisis de tiempos de ejecución <ul><li>El tiempo de ejecución depende de las características concretas del problema a resolver. </li></ul><ul><li>En general, será de la forma: </li></ul><ul><ul><li>Tamaño de la tabla*Tiempo de rellenar cada elemento de la tabla. </li></ul></ul><ul><li>Un aspecto importante de los algoritmos de programación dinámica es que necesitan una tabla para almacenar los resultados parciales, que puede ocupar mucha memoria. </li></ul><ul><li>Además, algunos de estos cálculos pueden ser innecesarios. </li></ul>
  8. 8. <ul><li>Problema : Dado un conjunto de n tipos de monedas, cada una con valor c i , y dada una cantidad P , encontrar el número mínimo de monedas que tenemos que usar para obtener esa cantidad. </li></ul><ul><li>El algoritmo voraz es muy eficiente, pero sólo funciona en un número limitado de casos. </li></ul><ul><li>Utilizando programación dinámica: </li></ul><ul><ul><li>Definimos el problema en función de problemas más pequeños. </li></ul></ul><ul><ul><li>Determinar los valores de los casos base. </li></ul></ul><ul><ul><li>Definimos las tablas necesarias para almacenar los resultados de los subproblemas. </li></ul></ul><ul><ul><li>Establecemos una forma de rellenar las tablas y de obtener el resultado. </li></ul></ul>Problema del cambio de monedas
  9. 9. <ul><li>Definición de la ecuación recurrente: </li></ul><ul><li>Cambio (i, Q) , el problema de calcular el número mínimo de monedas necesario para devolver una cantidad Q , usando los i primeros tipos de monedas (es decir los tipos 1...i). </li></ul><ul><li>La solución de Cambio(i, Q) puede que utilice k monedas de tipo i o puede que no utilice ninguna. </li></ul><ul><ul><li>Si no usa ninguna moneda de ese tipo: Cambio(i, Q) = Cambio(i - 1, Q) </li></ul></ul><ul><ul><li>Si usa k monedas de tipo i: Cambio(i, Q) = Cambio(i, Q – k*c i ) + k </li></ul></ul><ul><li>En cualquier caso, el valor será el mínimo: </li></ul><ul><li>Cambio(i, Q) = min k=0,1,...,Q/ci {Cambio(i-1, Q-k* c i )+k} </li></ul><ul><li>Casos base: Cambio(i, Q) </li></ul><ul><li>Si (i  0) ó (Q<0) entonces no existe ninguna solución al problema, y Cambio(i, Q) = +  . </li></ul><ul><li>En otro caso para cualquier i >0, Cambio(i, 0) = 0. </li></ul>Problema del cambio de monedas
  10. 10. Problema del cambio de monedas <ul><li>Definición de las tablas utilizadas: </li></ul><ul><li>Necesitamos almacenar los resultados de todos los subproblemas. </li></ul><ul><li>El problema a resolver será: Cambio (n, P). </li></ul><ul><li>Por lo tanto, necesitamos una tabla de nxP, de enteros, que llamaremos D , siendo D[i, j ]= Cambio(i, j) . </li></ul><ul><li>Ejemplo. n= 3, P= 8, c= (1, 4, 6) </li></ul><ul><li>Forma de rellenar las tablas: </li></ul><ul><li>De arriba hacia abajo y de izquierda a derecha, aplicar la ecuación de recurrencia: </li></ul><ul><ul><li>D[i, j] = min k=0,1,...,Q/ci {D(i-1, Q-k* c i )+k} </li></ul></ul>
  11. 11. Problema del cambio de monedas <ul><li>Algoritmo. </li></ul><ul><li>Devolver-cambio (P: int; C: array [1..n] of int; var D: array [1..n, 0..P] of int); </li></ul><ul><li>para i = 1,2,...,n </li></ul><ul><li> D[i, 0] = 0 </li></ul><ul><li>para i = 1,2,...,n </li></ul><ul><li> para j = 1,2,...,P {Tener en cuenta si el valor } </li></ul><ul><li> D[i, j] = min k=0,1,...,Q/ci {D(i-1, Q-k* c i )+k} { cae fuera de la tabla} </li></ul><ul><li>Ejemplo. n= 3, P= 8, c= (1, 4, 6) </li></ul><ul><li>¿Cuál es el tiempo de ejecución del algoritmo? </li></ul><ul><li>¿Cómo es en comparación con el algoritmo voraz? </li></ul><ul><li>D[n, P]: número mínimo de monedas que hay que usar para devolver la cantidad P. </li></ul>
  12. 12. Problema del cambio de monedas <ul><li>¿Cómo calcular cuántas monedas de cada tipo deben usarse, es decir la solución (x 1 , x 2 , ..., x n )? </li></ul><ul><li>Se usa otra tabla de decisiones tomadas: </li></ul><ul><ul><ul><li>Aux </li></ul></ul></ul><ul><li>Algoritmo para obtener una solución: </li></ul><ul><ul><li>para i=n,n-1,...,1 </li></ul></ul><ul><ul><li>x i =Aux[i,P] </li></ul></ul><ul><ul><li>P=P-x i *c i </li></ul></ul><ul><li>¿Cuál es el tiempo de ejecución del algoritmo para obtener la solución? </li></ul><ul><li>¿Es aplicable el principio de optimalidad? </li></ul>
  13. 13. Problema de la mochila 0/1 <ul><li>Igual que en el tema anterior, pero los objetos no se pueden fragmentar en trozos más pequeños. </li></ul><ul><li>Problema: Tenemos n objetos, cada uno con un peso ( w i ) y un beneficio ( v i ), y una mochila en la que podemos meter objetos, con una capacidad de peso máximo M . El objetivo es maximizar el beneficio de los objetos transportados, donde cada objeto se puede coger entero (x i =1) o nada (x i =0). </li></ul><ul><li>Definición de la ecuación recurrente: </li></ul><ul><li>Sea Mochila (i, m) el problema de la mochila, considerando sólo los i primeros objetos (de los n originales) con una capacidad de peso m . Supondremos que devuelve el valor de beneficio total:  x a ·v a </li></ul><ul><li> a=1..i </li></ul><ul><li>Podemos definir el problema de forma recurrente, en función de que se use o no el objeto i . </li></ul>
  14. 14. Problema de la mochila 0/1 <ul><li>Definición de la ecuación recurrente: </li></ul><ul><li>Si no se usa el objeto i : Mochila (i, m) = Mochila (i - 1, m) </li></ul><ul><li>Si se usa: Mochila (i, m) = v i + Mochila (i - 1, m - w i ) </li></ul><ul><li>Valor óptimo: </li></ul><ul><li>Mochila (i, m) = max (Mochila (i-1, m), v i + Mochila (i-1, m - w i )) </li></ul><ul><li>Casos base: </li></ul><ul><li>Si (i<0) o (m<0) entonces no hay solución: Mochila (i, m) = -  </li></ul><ul><li>En otro caso, si (i=0) ó (m=0) la solución es no incluir ningún objeto: Mochila (i, m) = 0 </li></ul><ul><li>Definición de las tablas: </li></ul><ul><li>La solución del problema original será Mochila (n, M). </li></ul><ul><li>Por lo tanto necesitamos una tabla: V : array [0..n, 0..M] of integer. </li></ul><ul><li>V[i, j] = Beneficio máximo usando los i primeros objetos y peso j. </li></ul>
  15. 15. Problema de la mochila 0/1 <ul><li>Forma de rellenar las tablas: </li></ul><ul><li>Inicializar los casos base. </li></ul><ul><li>Para todo i, desde 1 hasta n, y j desde 1 hasta M, aplicar la ecuación de recurrencia: </li></ul><ul><ul><li>V[i, j] = max (V[i - 1, j] , V[i - 1, j - w i ] + v i ) </li></ul></ul><ul><li>Si j es negativo, entonces V[i, j ] = -  , y el máximo será el otro término. </li></ul><ul><li>Ejemplo. n= 3, M= 6, w= (2, 3, 4), v= (1, 2, 5) </li></ul><ul><li>Tiempo de ejecución :  (nM). </li></ul>
  16. 16. Problema de la mochila 0/1 <ul><li>Se puede tener una tabla auxiliar de 0/1 para almacenar las decisiones parciales y recomponer la solución, o </li></ul><ul><li>A partir de la tabla V obtener la solución (x 1 , x 2 , ..., x n ) : partir de la posición V[n, M] y analizar las decisiones que se tomaron para cada objeto i . </li></ul><ul><ul><li>Si (V[i, j] = V[i-1, j]) entonces la solución no usa el objeto i , x i = 0. </li></ul></ul><ul><ul><li>Si (V[i, j] = V[i-1, j-w i ] + v i ) entonces sí se usa el objeto i , x i = 1. </li></ul></ul><ul><ul><li>Si (V[i, j] = V[i-1, j-w i ] + v i ) y (V[i, j] = V[i-1, j]) entonces podemos usar el objeto i o no (existe más de una solución óptima). </li></ul></ul><ul><ul><li>Acabar cuando lleguemos a un i=0 ó j=0. </li></ul></ul><ul><li>¿Cuál será el tiempo de recomponer la solución? </li></ul><ul><li>¿Se cumple el principio de optimalidad? </li></ul>

×