SESION 3-1 Programacion Dinamica
SESION 3-1 Programacion Dinamica
SESION 3-1 Programacion Dinamica
Programación Dinámica
Programación Dinámica
◼ Introducción
◼ Elementos de la programación dinámica
◼ Principio de optimalidad de Bellman
◼ Definición recursiva de la solución óptima
◼ Cálculo de la solución óptima
◼ Ejemplos
◼ Multiplicación encadenada de matrices
◼ Subsecuencia de mayor longitud (LCS)
◼ Selección de actividades con pesos
◼ Problema de la mochila
◼ Caminos mínimos: Algoritmos de Floyd y Bellman-Ford
◼ Distancia de edición
◼ Aplicaciones 1
Programación Dinámica
Programación Dinámica
Esta técnica se aplica sobre problemas que presentan
las siguientes características:
Programación Dinámica
Programación Dinámica
Enfoque ascendente (bottom-up):
◼ Primero se calculan las soluciones óptimas para
problemas de tamaño pequeño.
◼ Luego, utilizando dichas soluciones, encuentra
soluciones a problemas de mayor tamaño.
Clave: Memorización
Almacenar las soluciones de los subproblemas en
alguna estructura de datos para reutilizarlas
posteriormente. De esa forma, se consigue un
algoritmo más eficiente que la fuerza bruta, que
resuelve el mismo subproblema una y otra vez.
3
Programación Dinámica
Programación Dinámica
Memorización
Para evitar calcular lo mismo varias veces:
◼ Cuando se calcula una solución, ésta se almacena.
◼ Antes de realizar una llamada recursiva para un
subproblema Q, se comprueba si la solución ha sido
obtenida previamente:
◼ Si no ha sido obtenida, se hace la llamada recursiva
y, antes de devolver la solución, ésta se almacena.
◼ Si ya ha sido previamente calculada, se recupera la
solución directamente (no hace falta calcularla).
◼ Usualmente, se utiliza una matriz que se rellena
conforme las soluciones a los subproblemas son
calculados (espacio vs. tiempo). 4
Programación Dinámica
Programación Dinámica
Uso de la programación dinámica:
5
Programación Dinámica
Estrategias de diseño
Algoritmos greedy:
Se construye la solución incrementalmente, utilizando
un criterio de optimización local.
Programación dinámica:
Se descompone el problema en subproblemas
solapados y se va construyendo la solución con las
soluciones de esos subproblemas.
Divide y vencerás:
Se descompone el problema en subproblemas
independientes y se combinan las soluciones de
esos subproblemas.
6
Programación
Principio de Dinámica
Optimalidad
Para poder emplear programación dinámica, una
secuencia óptima debe cumplir la condición de que
cada una de sus subsecuencias también sea óptima:
7
Programación Dinámica
Principio de Optimalidad
En otras palabras:
Programación
Principio de Dinámica
Optimalidad
Un poco de historia: Bellman, años 50…
9
Richard E. Bellman: “Eye of the Hurricane: An Autobiography”
Programación Dinámica
Principio de Optimalidad
Principio de Optimalidad de Bellman
[Bellman, R.E.: “Dynamic Programming”. Princeton University Press, 1957]
Programación
Principio de Dinámica
Optimalidad
Principio de Optimalidad de Bellman
[Bellman, R.E.: “Dynamic Programming”. Princeton University Press, 1957]
¡Ojo!
El principio de optimalidad no nos dice que,
si tenemos las soluciones óptimas de los subproblemas,
entonces podamos combinarlas para obtener la solución
óptima del problema original…
11
Programación Dinámica
Principio de Optimalidad
Principio de Optimalidad de Bellman
[Bellman, R.E.: “Dynamic Programming”. Princeton University Press, 1957]
Programación Dinámica
Definición del problema…
Para aplicar programación dinámica:
13
Programación Dinámica
… y cálculo de la solución óptima
3. Se calcula el valor de la solución óptima utilizando un
enfoque ascendente:
◼ Se determina el conjunto de subproblemas que
hay que resolver (el tamaño de la tabla).
◼ Se identifican los subproblemas con una
solución trivial (casos base).
◼ Se van calculando los valores de soluciones
más complejas a partir de los valores
previamente calculados.
ProgramaciónDinámica
Programación Dinámica
Ejemplos
Sucesión de Fibonacci fib(n) = fib(n −1) + fib(n − 2)
◼ Implementación inmediata… n = n!
p p!( n − p )!
◼ Implementación usando programación dinámica…
Triángulo de Pascal
n = n −1 + n −1
p p −1 p
16
Programación Dinámica
Ejemplos
Números combinatorios: n = n −1 + n −1
Combinaciones de n sobre p −1
p p p
ProgramaciónDinámica
Programación Dinámica
Ejemplos
Números combinatorios: n = n −1 + n −1
Combinaciones de n sobre p −1
p p p
int combinaciones (int n, int p)
{
b[0] = 1;
for (i=1; i<=n; i++) {
b[i] = 1;
for (j=i–1; j>0; j--) {
b[j] += b[j – 1];
}
}
return b[p];
}
19
Orden de eficiencia: (np) en tiempo, (n) en espacio.
Programación Dinámica
Programación Dinámica
Devolver el cambio…
Existen casos para los que no se puede aplicar el
algoritmo greedy (por ejemplo, devolver 8 peniques
con monedas de 6, 4 y 1 penique).
ProgramaciónDinámica
Programación Dinámica
Devolver el cambio…
0 1 2 3 4 5 6 7 8
{1} 0 1 2 3 4 5 6 7 8
{1,4} 0 1 2 3 1 2 3 4 2
{1,4,6} 0 1 2 3 1 2 1 2 2
m={1,4,6}, C=8
Solución: 2 monedas, S={4,4}.
21
Programación Dinámica
Programación Dinámica
Multiplicación encadenada de matrices
Propiedad asociativa del producto de matrices:
“Parentizaciones” posibles:
n−1 1 si n =1 4n
P(n) = P(k)P(n − k) 2
k =1
si n 1
n
22
ProgramaciónDinámica
Programación Dinámica
Multiplicación encadenada de matrices
Si cada matriz Ak tiene un tamaño pk-1pk,
el número de multiplicaciones necesario será:
De forma general:
◼ Si i≠j, entonces
m(i, j) = minm(i, k) + m(k +1, j) + p i−1 pk p j
ik j
ProgramaciónDinámica
Programación Dinámica
Multiplicación encadenada de matrices
Implementación:
25
Programación Dinámica
Programación Dinámica
Multiplicación encadenada de matrices
Implementación:
for (i=1; i<=n; i++)
m[i,i] = 0;
ProgramaciónDinámica
Programación Dinámica
Multiplicación encadenada de matrices
Implementación:
// Suponiendo que hemos calculado previamente s[i,j]…
MultiplicaCadenaMatrices (A, i, j)
{
if (j>i) {
x = MultplicaCadenaMatrices (A, i, s[i,j]); y =
MultplicaCadenaMatrices (A, s[i,j]+1, j); return
MultiplicaMatrices(x, y);
} else {
return A[i];
}
}
27
Programación Dinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Problema:
Ejemplo:
Cadenas:
X = (A B C B D A B),
Y = (B D C A B A),
X = ( A B C B D A B )
Y = ( B D C A B A ) 28
ProgramaciónDinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Un algoritmo de fuerza bruta compararía cualquier
subsecuencia de X con los símbolos de Y:
Xi Prefijo de X de longitud i.
Yj Prefijo de Y de longitud j.
c(i,j) Longitud de la LCS para Xi e Yj.
ProgramaciónDinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Definición recursiva de la solución:
◼ Caso base:
c(0,0) = 0 (Subcadena vacía)
c(0,j) = c(i,0) = 0 (LCS de la cadena vacía
y cualquier otra cadena)
◼ Cálculo recursivo:
◼ Primer caso (x[i]=y[j]=s): Se emparejan ambos
símbolos y la LCS aumenta de longitud:
LCS(Xi,Yj)= LCS(Xi-1,Yj-1)+{s}.
◼ Segundo caso (x[i]≠y[j]): No se pueden emparejar
los símbolos x[i] e y[j], por lo que LCS(Xi,Yj) será
la mejor entre LCS(Xi-1,Yj) y LCS(Xi,Yj-1). 31
Programación Dinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Implementación iterativa del algoritmo:
return c;
} 32
ProgramaciónDinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Ejemplo:
Yj B D C A B
X = (A B C B), 0 1 2 3 4 5
Y = (B D C A B),
Xi 0 0 0 0 0 0 0
A 1 0
B 2 0
C 3 0
B 4 0
if ( X[i] == Y[j] )
c[i][j] = c[i-1][j-1] + 1;
else
c[i][j] = max ( c[i-1][j], c[i][j-1] ); 34
ProgramaciónDinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Ejemplo:
Yj B D C A B
X = (A B C B), 0 1 2 3 4 5
Y = (B D C A B),
Xi 0 0 0 0 0 0 0
A 1 0 0 0 0 1
B 2 0
C 3 0
B 4 0
if ( X[i] == Y[j] )
c[i][j] = c[i-1][j-1] + 1;
else
c[i][j] = max ( c[i-1][j], c[i][j-1] ); 35
Programación Dinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Ejemplo:
Yj B D C A B
X = (A B C B), 0 1 2 3 4 5
Y = (B D C A B),
Xi 0 0 0 0 0 0 0
A 1 0 0 0 0 1 1
B 2 0
C 3 0
B 4 0
if ( X[i] == Y[j] )
c[i][j] = c[i-1][j-1] + 1;
else
c[i][j] = max ( c[i-1][j], c[i][j-1] ); 36
ProgramaciónDinámica
Programación Dinámica
Subsecuencia de mayor longitud (LCS)
Ejemplo:
Yj B D C A B
X = (A B C B), 0 1 2 3 4 5
Y = (B D C A B),
Xi 0 0 0 0 0 0 0
LCS = (B C B) A 1 0 0 0 0 1 1
B 2 0 1 1 1 1 2
X = ( A B C B )
C 3 0 1 1 2 2 2
Y = ( B D C A B )
B 4 0 1 1 2 2 3
NOTA:
A partir del valor c[i][j] podemos determinar cómo
se calculó éste y encontrar la LCS hacia atrás… 37
Programación Dinámica
Programación Dinámica
Selección de actividades con pesos
Enunciado del problema
ProgramaciónDinámica
Programación Dinámica
Selección de actividades con pesos
Recordatorio
valor = 999 b
valor = 1 a
39
Programación Dinámica
Programación Dinámica
Selección de actividades con pesos
Observación
Si, como en el algoritmo greedy, ordenamos las
actividades por su hora de finalización…
8 Tiempo 40
ProgramaciónDinámica
Programación Dinámica
Selección de actividades con pesos
Observación
… podemos definir p(j) como el mayor índice i<j
tal que la actividad i es compatible con la actividad j
p(1)=0
p(2 )=0
p(3)=0
p(4)=1
p(5)=0
p(6 )=2
p(7 )=3
p(8)=5 Tiempo 41
Programación Dinámica
Programación Dinámica
Selección de actividades con pesos
Definición recursiva de la solución
0 si j =0
OPT ( j) =
max{v( j) + OPT ( p( j)),OPT ( j −1)} si j 0
ProgramaciónDinámica
Programación Dinámica
Selección de actividades con pesos
Implementación iterativa del algoritmo
mejor[0] = 0; // O(1)
for (i=1; i<=n, i++) // O(n)
mejor[i] = max ( valor[i]+mejor[p[i]],
mejor[i-1] );
Objetivo: Seleccionar
los elementos que nos
garantizan un beneficio
máximo pero pero con
un peso global menor
o igual que W.
44
ProgramaciónDinámica
Programación Dinámica
El problema de la mochila 0/1
Dado el conjunto S de n objetos,
sea Sk el conjunto de los k primeros objetos (de 1 a k):
45
Programación Dinámica
Programación Dinámica
El problema de la mochila 0/1
¿Cómo calculamos B(k,w)?
46
ProgramaciónDinámica
Programación Dinámica
El problema de la mochila 0/1
Definición recursiva de B(k,w):
B(k −1,w) si xk = 0
B(k,w) =
B(k −1, w − wk ) + b k si xk =1
47
Programación Dinámica
Programación Dinámica
El problema de la mochila 0/1
Cálculo ascendente de B(k,w)
usando una matriz B de tamaño (n+1) x (W+1):
return B; 48
}
ProgramaciónDinámica
Programación Dinámica
El problema de la mochila 0/1
¿Cómo calculamos la solución óptima a partir de B(k,w)?
Si B[k][w] == B[k-1][w],
entonces el objeto k no se selecciona y se seleccionan
los objetos correspondientes a la solución óptima para
k-1 objetos y una mochila de capacidad w:
la solución para B[k-1][w].
Si B[k][w] != B[k-1][w],
se selecciona el objeto k
y los objetos correspondientes a la solución óptima
para k-1 objetos y una mochila de capacidad w-w[k]:
la solución para B[k-1][w-w[k]].
49
Programación Dinámica
Programación Dinámica
El problema de la mochila 0/1
Eficiencia del algoritmo
ProgramaciónDinámica
Programación Dinámica
El problema de la mochila 0/1
Ejemplo Objeto Valor Peso
Mochila de tamaño W=11 1 1 1
Número de objetos n=5 2 6 2
3 18 5
Solución óptima {3,4} 4 22 6
5 28 7
0 1 2 3 4 5 6 7 8 9 10 11
0 0 0 0 0 0 0 0 0 0 0 0
{1} 0 1 1 1 1 1 1 1 1 1 1 1
{ 1, 2 } 0 1 6 7 7 7 7 7 7 7 7 7
{ 1, 2, 3 } 0 1 6 7 7 18 19 24 25 25 25 25
{ 1, 2, 3, 4 } 0 1 6 7 7 18 22 24 28 29 29 40
{ 1, 2, 3, 4, 5 } 0 1 6 7 7 18 22 28 29 34 35 40 51
Programación Dinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Floyd
Problema:
Calcular el camino más corto que une cada par de
vértices de un grafo, considerando que no hay pesos
negativos.
Posibles soluciones:
ProgramaciónDinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Floyd
Definición recursiva de la solución:
Expresión recursiva:
Caso base:
D0 (i, j) = cij
53
Programación Dinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Floyd
Algoritmo de Floyd (1962): (V 3 )
ProgramaciónDinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Bellman-Ford
2 3
s
1 -6
t
¡Ojo!
Tampoco podemos sumarle una constante a cada peso. 55
Programación Dinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Bellman-Ford
si i = 0
Di (w)= min{D
i−1 (w), min {Di−1 (v) + cvw }} en otro caso
(v,w)E
ProgramaciónDinámica
Programación Dinámica
Caminos mínimos: Algoritmo de Bellman-Ford
Algoritmo de Bellman-Ford: (EV)
foreach v V {
D[v] = ;
predecesor[v] = null;
}
D[s] = 0;
for (i=1; i<n; i++) {
foreach (v, w) E {
if (D[v] + coste(v,w) < D[w]) {
D[w] = D[v] + coste(v,w);
predecesor[w] = v;
}
}
} 57
Programación Dinámica
Programación Dinámica
Distancia de edición
También conocida como distancia Levenshtein, mide
la diferencia entre dos cadenas s y t como el número
mínimo de operaciones de edición que hay que
realizar para convertir una cadena en otra:
ProgramaciónDinámica
Programación Dinámica
Distancia de edición
Definición recursiva de la solución
CASOS
◼ Mismo carácter: d(i-1,j-1)
◼ Inserción: 1 + d(i-1,j)
◼ Borrado: 1 + d(i,j-1)
◼ Modificación: 1 + d(i-1,j-1)
59
Programación Dinámica
Programación Dinámica
Distancia de edición
int LevenshteinDistance (string s[1..m], string t[1..n])
{
for (i=0; i<=m; i++) d[i,0]=i;
for (j=0; j<=n; j++) d[0,j]=j;
return d[m,n];
}
ProgramaciónDinámica
Programación Dinámica
Aplicaciones
◼ Distancia entre dos series temporales: O(n2)
DTW [Dynamic Time Warping]
◼ Análisis sintáctico: O(n3)
◼ Algoritmo CKY [Cocke-Kasami-Younger]
◼ Algoritmo de Earley
◼ Algoritmo de Viterbi: HMMs [Hidden Markov Models]
◼ Decodificación de señales (p.ej. modems, GSM, wi-fi)
◼ Procesamiento del lenguaje natural
◼ Bioinformática
◼ Optimización de consultas en bases de datos relacionales
◼ Comparación de ficheros con diff
◼ … 61