1
Contenido
2
Programación Dinámica
1) Introducción:
1. El problema se puede dividir en etapas que requieren una política de decisión en cada
una de ellas. En muchos problemas de programación dinámica, la etapa es la cantidad
de tiempo que pasa desde el inicio del problema, en ciertos casos no se necesitan
decisiones en cada etapa.
2. Cada etapa tiene un cierto número de estados asociados a ella. Por estado se entiende
la información que se necesita en cualquier etapa para tomar una decisión óptima.
3. El efecto de la política de decisión en cada etapa es transformar el estado actual en un
estado asociado con la siguiente etapa (tal vez de acuerdo a una distribución de
probabilidad).
4. El procedimiento de solución está diseñado para encontrar una política óptima para el
problema completo, es decir, una receta para las decisiones de la política óptima en
cada etapa para cada uno de los estados posibles.
3
5. Dado el estado actual, una política óptima para las etapas restantes es independiente
de la política adoptada en etapas anteriores. (este es el principio de óptimalidad para la
programación dinámica). En general en los problemas de PD, el conocimiento del estado
actual del sistema expresa toda la información sobre su comportamiento anterior, y esta
información es necesario para determinar la política óptima de ahí en adelante.
6. El procedimiento de solución se inicia al encontrar la política óptima para la última
etapa. La política óptima para la última etapa prescribe la política óptima de decisión
para cada estado posible en esa etapa.
7. Se dispone de una relación recursiva que indica la política óptima para la etapa dada la
política óptima para la etapa (n+1) .
A pesar de esta característica, los problemas que pueden ser atacados con la PD tienen otras
dos propiedades adicionales:
Sólo un número reducido de variables se debe conocer en cualquier etapa con el fin de
describir al problema. En efecto, los problemas de la PD se caracterizan por la
dependencia de los resultados derivados de decisiones sobre un número reducido de
variables.
El resultado de una decisión en cualquier etapa altera los valores numéricos de un
número reducido de variables relevantes al problema. La decisión actual ni incrementa
ni decrementa el número de factores sobre los cuales depende el resultado. Así, para la
siguiente decisión en la secuencia, el mismo número de variables se considera (Hillier,
1991).
NOTA:
2.2) Aplicaciones:
Algunas de las aplicaciones de programación dinámica determinística son:
A continuación, se presentarán algunas de estas aplicaciones, cada una de las cuales muestra
una nueva idea en la puesta en práctica de la PD.
i=1, 2,3…n
A medida que se presente cada aplicación, es importante prestar atención a los tres elementos
básicos de un modelo de PD:
4
Definición de las etapas.
Definición de los estados para cada etapa De los tres elementos, la definición del estado por lo
común es la más sutil. Las aplicaciones que se presentan a continuación muestran que la
definición de estado varía dependiendo de la situación que se está modelando.
Si (n<2)
Devolver 1
Sino
Devolver Fibonacci(n-1) + Fibonacci (n-2)
5
T [0] = 0 T [1] = 1
Para i = 2, 3, 4…n
T [i] = T [i-1] +T [i-2]
Devolver T [n]
Se utiliza la misma fórmula que la versión anterior, pero de forma más inteligente. El
tiempo de ejecución es mínimo
6
Por lo tanto necesitamos una tabla de n *P, de enteros, que llamaremos D
siendo D[i,j] =Cambio (i,j)
Ejemplo:
n=3, P=8, c= (1,4,6)
D Cantidad a devolver
Monedas 0 1 2 3 4 5 6 7 8
𝐶1
𝐶2
𝐶3
Algoritmo:
Devolver_cambio( P : int ; C : array[ 1…n] of int ; var D :[ 1..n ,0….P ]of int)
Para i = 1, 2,3……n
D [i, 0] =0
Para i = 1, 2,3……n
Para j = 1, 2,3……P
D [i, j]= 𝑘 = 0,1,2. . 𝑄 𝑚𝑖𝑛 {Cambio (i, Q) = Cambio (i-1, Q- k*𝑐𝑖 ) +k}
Fin
D Cantidad a devolver
Monedas 0 1 2 3 4 5 6 7 8
𝐶1 0 1 2 3 4 5 6 7 8
𝐶2 0 1 2 3 1 2 3 4 2
𝐶3 0 1 2 3 1 2 1 2 2
7
Parecido al problema anterior, pero los objetos no se pueden fragmentar en problemas
más pequeños.
Problema: Tenemos n objetos cada uno con un peso 𝑤𝑖 y un beneficio 𝑉𝑖 y una mochila
en lo 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 𝑥𝑖 =1 o 𝑥0 = 0 .
Caso base:
Si ((i<0) o (m<0)) entonces no hay solución: Mochila (i, m) = -∞
En otro caso, si (i=0 o m=0) la solución es no incluir ningún objeto: Mochila (i, m) =0
Definición de las tablas
La solución del problema original será Mochila (n, M). Por lo tanto necesitamos una tabla
V: Array [0…n, 0….m] of interger
V [i, j] =Beneficio máximo usando los i primeros objetos y peso j
0 1 2 3 4 5 6
0 0 0 0 0 0 0 0
1 0 0 1 1 1 1 1
2 0 0 1 2 2 3 3
3 0 0 1 2 5 5 6
8
3.4) Coeficientes binomiales:
El algoritmo recursivo que calcula los coeficientes binomiales resulta ser de complejidad
exponencial por la repetición de los cálculos que realiza. No obstante, es posible diseñar
un algoritmo con un tiempo de ejecución de orden O (nk) basado en la idea del Triángulo
de Pascal, idea claramente aplicable mediante programación dinámica. Para ello es
necesaria la creación de una tabla bidimensional en la que ir almacenando los valores
intermedios que se utilizan posteriormente.
(𝑛𝑘) = (𝑛−1
𝑘−1
) + ( 𝑛−1
𝑘
) si 0<k<n
(𝑛0) = (𝑛𝑛) = 1
0 1 2 3 …… k-1 k
….. …. …… …… …..
…. ….. ……. …… …… ……
n C(n,k)
9
El siguiente algoritmo memorizado de estrategia Bottom-up tiene complejidad polinómica y
va rellenando la tabla de izquierda a derecha y de arriba abajo:
10
3.5) INTERESES BANCARIOS:
Dadas n funciones f1, f2, ..., fn y un entero positivo M, deseamos maximizar la función
f1(x1) + f2(x2) + ... + fn(xn) sujeta a la restricción x1 +x2 + ... + xn = M, donde fi(0) = 0
(i=1,..,n), xi son números naturales, y todas las funciones son monótonas crecientes, es
decir, x ≥ y implica que fi(x) > fi(y). Supóngase que los valores de cada función se
almacenan en un vector.
Este problema tiene una aplicación real muy interesante, en donde fi representa la
función de interés que proporciona el banco i, y lo que deseamos es maximizar el interés
total al invertir una cantidad determinada de dinero M. Los valores xi van a representar
la cantidad a invertir en cada uno de los n bancos.
Solución
Sea fi un vector que almacena el interés del banco i (1 ≤ i ≤ n) para una inversión de 1,
2, 3,..., M soles. Esto es, fi (j) indicará el interés que ofrece el banco i para j soles, con 0
< i ≤ n, 0 < j ≤ M. Para poder plantear el problema como una sucesión de decisiones,
llamaremos In(M) al interés máximo al invertir M soles en n bancos,
In(M) = f1(x1) + f2(x2) + ... + fn(xn)
que es la función a maximizar, sujeta a la restricción x1 +x2 + ... + xn = M. Veamos cómo
aplicar el principio de óptimo. Si In(M) es el resultado de una secuencia de decisiones y
resulta ser óptima para el problema de invertir una cantidad M en n bancos, cualquiera
de sus subsecuencias de decisiones ha de ser también óptima y así la cantidad I n–1(M –
xn) = f1(x1) + f2(x2) + ... + fn–1(xn–1) será también óptima para el subproblema de
invertir (M – xn) soles en n – 1 bancos.
Y por tanto el principio de óptimo nos lleva a plantear la siguiente relación en
recurrencia:
Para resolverla y calcular In(M), vamos a utilizar una matriz I de dimensión nxM en donde
iremos almacenando los resultados parciales y así eliminar la repetición de los cálculos.
El valor de I[i,j] va a representar el interés de j soles cuando se dispone de i bancos, por
tanto la solución buscada se encontrará en I[n,M]. Para guardar los datos iniciales del
problema vamos a utilizar otra matriz F, de la misma dimensión, y donde F[i,j] representa
el interés del banco i para j soles. En consecuencia, para calcular el valor pedido de I[n,M]
rellenaremos la tabla por filas, empezando por los valores iniciales de la ecuación en
recurrencia, y según el siguiente algoritmo:
11
CONST n =...; (* número de bancos *)
M =...; (* cantidad a invertir *)
TYPE MATRIZ = ARRAY [1...n], [0...M] OF CARDINAL;
PROCEDURE Intereses (VAR F: MATRIZ; VAR I: MATRIZ): CARDINAL;
VAR i,j: CARDINAL;
BEGIN
FOR i:=1 TO n DO I [i, 0]:=0 END;
FOR j:=1 TO M DO I [1, j]:=F [1, j] END;
FOR i:=2 TO n DO
FOR j:=1 TO M DO
I [i,j]:=Max(I,F,i,j)
END
END;
RETURN I [n,M]
END Intereses;
La función Max es la que calcula el máximo que aparece en la expresión [5.1]::
PROCEDURE Max (VAR I,F:MATRIZ;i,j:CARDINAL):CARDINAL;
VAR max,t:CARDINAL;
BEGIN
max:= I[i-1,j] + F[i,0];
FOR t:=1 TO j DO
max:=Max2(max,I[i-1,j-t]+F[i,t])
END;
RETURN max
END Max;
12
Es importante hacer notar el uso de parámetros por referencia en lugar de por valor
para evitar la copia de las matrices en la pila de ejecución del programa. Por otro lado,
la complejidad espacial del algoritmo es del orden O(nM), pues de este orden son las
dos matrices que se utilizan para almacenar los resultados intermedios.
En este ejemplo queda de manifiesto la efectividad del uso de estructuras en los
algoritmos de Programación Dinámica para conseguir obtener tiempos de ejecución de
orden polinómico, frente a los tiempos exponenciales de los algoritmos recursivos
iniciales.
La idea de esta segunda expresión surge al observar que en cualquiera de los trayectos
siempre existe un primer salto inicial óptimo.
13
Para resolverla según la técnica de Programación Dinámica, hace falta utilizar una
estructura para almacenar resultados intermedios y evitar la repetición de los cálculos.
La estructura que usaremos es una matriz triangular de costes C [i,j], que iremos
rellenando por diagonales mediante el procedimiento que hemos denominado Costes.
La solución al problema es la propia tabla, y sus valores C [i,j] indican el coste óptimo
para ir del embarcadero i al j.
CONST MAXEMBARCADEROS =...;
TYPE MATRIZ=ARRAY [1...MAXEMBARCADEROS], [1...MAXEMBARCADEROS] OF
CARDINAL;
PROCEDURE Costes (VAR C: MATRIZ; n: CARDINAL);
VAR i, diagonal: CARDINAL;
BEGIN
FOR i:=1 TO n DO C[i,i]:=0 END; (* condiciones iniciales *)
FOR diagonal:=1 TO n-1 DO
FOR i:=1 TO n-diagonal DO
C[i,i+diagonal]:=Min(C,i,i+diagonal)
END
END
END Costes;
Dicho procedimiento utiliza la siguiente función, que permite calcular la expresión del
mínimo que aparece en la ecuación en recurrencia [5.2]:
PROCEDURE Min(VAR C:MATRIZ; i,j:CARDINAL):CARDINAL;
VAR k,min:CARDINAL;
BEGIN
min:=MAX(CARDINAL);
FOR k:=i+1 TO j DO
min:=Min2(min,T[i,k] + C[k,j])
END;
RETURN min
END Min;
La función Min2 es la que calcula el mínimo de dos números naturales. Es importante
observar que esta función, por la forma en que se va rellenando la matriz C, sólo hace
14
uso de los elementos calculados hasta el momento. La complejidad del algoritmo es de
orden O (n3), pues está compuesto por dos bucles anidados de tamaño n, que contienen
la llamada a una función de orden O(n), la que calcula el mínimo.
15
5)Ventajas y desventajas:
5.1) VENTAJAS
No se requiere de una formulación matemática compleja.
Los cálculos son sencillos.
Reduce un problema inmanejable a una serie de problemas más pequeños y manejables.
Es un método eficiente.
5.2) DESVENTAJAS:
No siempre se puede aplicar a todos los problemas.
16