rogramacién dinamica
En el capitulo anterior vefamos que es posible dividir los ejemplares en sul
jemplares, resolver los subejemplares (posiblemente, subdividiéndolos
nuevo) y combinar entonces las soluciones de los subejemplares para resol
el caso original. A veces sucede que la forma natural de dividir un ejemplar,
como lo sugiere la estructura del problema, nos lleva a considerar subejemp
res solapados. Si los resolvemos todos independientemente, éstos darén a su
lugar a toda una coleccién de subejemplares idénticos. $i no prestamos aten
aesta duplicacién, es probable que acabemos por tener un algoritmo ineficier
si por el contrario aprovechamos la duplicacién y nos las arreglamos para res
ver cada subejemplar una sola vez, guardando la solucién para su uso posteri
entonces tendremos un algoritmo mas eficiente. La idea que subyace a la p
gramacién dindmica es, por tanto, bastante sencilla: evitar calcular dos ve:
una misma cosa, normalmente manteniendo una tabla de resultados conacic
que se vaya Ilenando a medida que se resuelven los subcasos.
El método de divide y vencerds es un método de refinamiento progresivo. Cus
do se resuelve un problema mediante divide y vencerds, atacamos de inmedi:
el. caso completo, que a continuacién dividimos en subcasos mds y més pequeA
a medida que progresa el algoritmo. La programacién dindmica, por otra parte,
una técnica ascendente. Normalmente, se empieza por los subcasos mas pequen
y por tanto més sencillos. Combinando sus soluciones, obtenemos las respues
para subcasos de tamaios cada vez mayores, hasta que finalmente llegamos ¢
solucién del caso original
‘Comenzaremos el capitulo por dos ejemplos sencillos de programacién dinar
ca, que ilustran la técnica general en una situacién poco complicada. Las secciotProgramacién dindmica Capitule
siguientes abordan los problemas de devolver cambio, que mencionébamos en
Seccién 6.1, y el dela mochila, que encontrébamos en la Seccidn 65.
8.1 DOS EJEMPLOS SENCILLOS
8.1.1 Calculo del coeficiente binomial
‘Considere el problema consistente en calcular el coeficiente binomial
ff) seer
‘Supongamos que 0 SS 1, Si calculamos directamente ({) mediante
funei6n CC, b)
sik =00k=n entonces devolver 1
sino devolver C(—1, k-1) + Cit-1,
entonces muchos de los valores de C(i, j), con # 1
en donde ¢ y d son constantes. Reescribiendo T(k-1) en términos de TUk-2), ¥ asi
sucesivamente, obtenemosCapitulc
TU) <4T(k-2)+ ded, kod
S2UITUD + (244 Be DED
= he 4 (Dt
= Me/2#d/2t
Por tanto TU) esté en O12, que es O14") si i = j= st, De hecho, si examinamos
forma en que se generan las lamadas recursivas, encontramos e] patron que
muestra en la figura 8.2, que es idéntico al calculo menos sofisticado del cor
ciente binomial, Para ver esto imaginemos que toda llamada a Pins, n) en la fig
ra se sustituye por Cf + 11,1.
De esta manera, P(i, 1) se sustituye por Ci + i, ),Pli- 1, /) se sustituye |
CG + j-1, Py PG, FD se sustituye por Cli + j—1, 1). Ahora el patrén de flan
das que muestran las flechas corresponde al calculo
CU + P= CU + j-1, + CG 4j-1, 7-0)
de un coeficiente binomial. El mimero total de Ilamadas recursivas, por tanto,
exactamente de 2";")-2; véase el Problema 8.1. Asi pues para calcular la proba
lidad Pl, 2) de que el equipo A sea el ganador, dado que todavia no ha empe
do el campeonato, el tiempo requerido esta, por tanto, en Q' >.
PG, k corresponde a izquien
lama oa
PG-LD Pi j=. L corresponde a izquien
quellama ua ak
PG,-2,)) PU-Lf-1) PU, ,-2) k—2 corresponde a izquien
ete.
Figura 8.2, Hamadas recursivas efectuadas por una Uamada a Pe.)
E] Problema 1.42 pide al lector demostrar que "24" / Qi + D. Combinando
tos resultados, se ve que el tiempo necesario para calcular P(i, n) esta. en OCA
en QW / 1). El método, por tanto, no resulta practico para valores grandes de
(Aun cuando las competiciones deportivas con 1 > 4 sean la excepcién, jeste p
blema tiene otras aplicaciones!)
Para acelerar el algeritmo, procederemos mas menos igual que con el tri
gulo de Pascal: declaramos un vector del tamaito adecuado y después vamos
llenando las entradas. Esta vez, sin embargo, en lugar de ir llenando el vector
nea por linea, vamos. a trabajar diagonal por diagonal. Este es el algoritmo p:
calcular Po, 1)cién 8.2 Devolver cambio (2).
funcién serie(, p)
matriz P(0..»,0..n)
qe l-p
{Llenamos desde la esquina izquierda hasta la diagonal principal}
para s+ 1 hasta n hacer
PIO, s) 1; Pls, 0] — 0
parak < 1 hasta s~1 hacer
lk, s-k] = pP[k-1, s—k] + P[k, s—k-1]
{Llenamos desde debajo de la diagonal principal hasta la esquina derecha}
paras ~ 1 hasta n hacer
para k < 0 hasta 1 ~s hacer
Pls + ky n-K]— PIs + k—1, n—Kl + qPls + k,n -k—1]
devolver Piri, 1]
Dado que el algoritmo tiene que Henar una matriz mx n, y dado que se necesita una
constante temporal para calcular cada entrada, su tiempo de ejecucién se encuentra
en O(rr). Aligual que en el triingulo de Pascal, resulta sencillo implementar este al-
goritme de tal manera que baste con un espacio de almacenamiento en @().
2 DEVOLVER CAMBIO (2)
Recuerde que el problema consiste en desarrollar un algoritmo para pagar una cier-
tacantidad a un cliente, empleando el menor nimero posible de monedas. En la Sec-
ci6n 6.1 describiamos un algoritmo voraz para este problema. Desafortunadamen-
te, aunque el algoritmo voraz es muy eficiente, funciona solamente en un niimero
limitado de casos. Con ciertos sistemas monetarios, o cuando faltan monedas de
una cierta denominacién (0 su nimero es limitado), el algoritmo puede encontrar
una respuesta que no sea dptima, o incluso puede no hallar respuesta ninguna.
Por ejemplo, supongamos que vivimos en un lugar en el cual hay monedas de
1,4 y 6 unidades. Si tenemos que cambiar & unidades, el algoritmo voraz propon-
drd hacerlo con una moneda de 6 unidades y dos de una unidad, con un total de
tres monedas. Sin embargo, estd claro que podemos hacerlo mejor: basta con dar
al cliente su cambio empleando tan sélo dos monedas de cuatro unidades. Aun-
que el algoritmo voraz no halla esta solucién, resulta sencillo obtenerla emplean-
do programacién dinamica.
Como en la seccién anterior, el guid del método consiste en preparar una ta-
bla que contenga resultados intermedias ittiles, que seran combinados en la so-
lucién del caso que estamos considerando. Supongamos que el sistema moneta-
rio que estamos considerando tiene monedas de 1 denominaciones diferentes, y
que una moneda de denominacién i, con 1« i< 1 tiene un valor de d, unidades.
Supondremos, como es habitual, que todos los d, > 0. Por el momento, supon-
dremos también que se dispone de un suministro ilimitado de monedas de cada
denominacién. Por ultimo, supongamos que tenemos que dar al cliente monedas
por valor de N unidades, empleando el menor nimero posible de monedas.6 Programacién dinamica Capitulo
Para resolver este problema mediante programaci6n dindmica, preparan
una tabla ¢[1..n, 0..N] con una fila para cada denominacién posible y una colum
para las cantidades que van desde 0 unidades hasta N unidades. En esta tabla,
j] serd el ntimero mfnimo de monedas necesarias para pagar una cantidad ck
unidades, con 0 = j < N, empleando solamente monedas de las denominaci
desde 1 hasta i, con 1 si <1. La solucién del ejemplar, por tanto, esta dada |
clu, N] si lo Gnico que necesitamos saber es el niimero de monedas que se nec¢
tan, Para rellenar la tabla, obsérvese primero que cli, 0) es cero para todos los
lores de f. Después de esta inicializacién, la tabla se puede rellenar o bien fila |
fila de izquierda a derecha, 0 bien columna por columna avanzando hacia ab:
Para abonar una cantidad j utilizando monedas de las. denominaciones entre 1
tenemos dos opciones en general. En primer lugar, podemos decidir que no ut
zaremos monedas de la denominacién i, aun cuando esto est permitido ahora,
cuyo caso cli, j] = efi - 1, j]. Como alternativa, podemos decidir que emplearen
al menos una moneda de la denominacién i. En este caso, una vez que hayan
entregado la primera moneda de esta denominaci6n, quedan por pagar j—d, u
dades. Para pagar esto se necesitan cli, j—d)] unidades, asi que cfi, j] = 1 + cli, j~
Dado que deseamos minimizar el némero de monedas utilizadas, seleccionaren
aquella alternativa que sea mejor. En general, por tanto:
cli, fl = min(cli-1, jJ+cli, j- 4)
‘Cuando i = 1, uno de los elementos que hay que comparar cae fuera de la tabla.
mismo sucede cuando j < d.. Resulta cémodo pensar que tales elementos poseet
valor +. Sii = 1 yj < d, entonces los dos elementos que hay que comparar cz
fuera de la tabla. En este caso, hacemos ¢[i, ] igual a +2 para indicar que es i
posible pagar una cantidad j empleando solamente monedas del tipo 1
La figura 8.3 ilustra el caso dado anteriormente, en el que teniamos que paj
8 unidades con monedas que valian 1, 4 y 6 unidades. Por ejemplo, c[3, 8] se «
tiene en este caso como el menor de c[2, §]= 2 y 1 + 43,8- dj = 1+ c[3,2] = 3.1
entradas en el resto de la tabla se obtienen de forma similar. La respuesta para
te caso concreto es que podemos pagar ocho unidades empleando tnicamente «
monedas. De hecho, la tabla nos da la solucién de nuestro problema para todos
casos que supongan un pago de 8 unidades o menos.
Cantidad: | 0 1 2 3 4 5 6 7 8
ae1 o 1 2 3 4 «5 6 7 8
= 4 o 1 2 3 1 2 3 4 2
4-6 o 1 2 3 12 1 2 2
Figura 8.3 Devolver cambio empleando programacién dinémica
\Véase a continuaci6n una versién mas formal del algoritmo:cién 8.2 Devolver cambio (2) 7
funeién mowedas(N)
{Devuelve el minimo niimero de monedas necesarias
para cambiar N unidades. Fl vector {1 .]
especifica las denominaciones: en el ejemplo hay monedas
de 1, 4 y 6 unidades}
vector d[1. = [1, 4, 6)
matriz.¢{1..i, O..N]
para i <1 hasta hacer cli, 0] —0
para i <1 hasta hacer
para j <— 1 hasta N hacer
sii
Ly j 0, > Oy x,€ 10, 1} para 1 Sin. Aqui las condiciones que afectan av, y
am; son limitaciones que afectan al caso; las de, son restricciones que afectan a la s0-
lucién, Dado que el problema se parece mucho al de la Seccién 6.5, es natural pre-
guntarse en primer lugar si una ligera modificacién del algoritme voraz que utilizé-
bamos antes podria funcionar ahora. Supongamos entonces que se adapta el algorit-
mo de la forma evidente, de tal modo que vaya examinando los objetos en orden des
cendente de valor por unidad de peso. Si la mochila no esta Ilena, el algoritmo tiene
que seleccionar un objeto completo si es posible, antes de pasar al siguiente.9. Programacién dindmica
Desafortunadamente, el algoritmo voraz no funciona cuando x, tiene que se
bien 0 o bien 1. Por ejemplo, supongamos que estan disponibles tres objetos, el p
mero de los cuales pesa 6 unidades y tiene un valor de 8, mientras que los ott
dos pesan 5 unidades cada uno y tienen un valor de 5 cada uno. Si la mochila pt
de llevar 10 unidades, entonces la carga éptima incluye a los dos objetos mas
eros, con un valor total de 10. E! algoritmo voraz, por otra parte, comenzaria p
seleccionar el objeto que pesa 6 unidades, puesto que es el que tiene un mayor +
lor por unidad de peso. Sin embargo, si los objetos no se pueden romper, el alg
ritmo no podra utilizar la capacidad restante de la mochila. La carga que produ:
por tanto, consta de un sole objeto, y tiene un valor de 8 nada mas.
Para resolver el problema por programacién dindmica, preparamos una tal
V{1..n, 0..] que tiene una fila para cada objeto disponible, y una columna pe
cada peso desde 0 hasta W. En la tabla, V\j, j] sera el valor maximo de los objet
que podemos transportar si el limite de peso es j, con 0-< j s W, si solamente
cluimos los objetos numerados desde el 1 hasta el i, con 1 si