Академический Документы
Профессиональный Документы
Культура Документы
1 Maximum Subarray
Dado un arreglo de n enteros, se debe determinar la suma máxima de un subarreglo de
enteros continuos.
Un algoritmo de fuerza bruta debe calcular la suma de todos los subarreglos posibles,
lo cual tomarı́a O(n3 ). Utilizando DP se puede calcular una solución parcial para cada
posición 0 ≤ i < n en el arreglo y almacenar la mejor entre estas. Cada solución parcial
representa el subarreglo máximo que sea un sufijo del subarreglo A[0...i]. Estas sumas se
pueden formular de las siguientes dos maneras:
i
X
S(i) = max { A[x]} (1)
j∈[0,i]
x=j
El planteamiento de la fórmula (1) necesita iterar a través del arreglo por lo menos una
vez, por lo que la complejidad total es de O(n2 ). Por otro lado, la ecuación (2) solo utiliza
valores ya calculados ası́ que este algoritmo, conocido como el algoritmo de Kadane, se
puede realizar en O(n).
1: procedure Max-Subarray(A)
2: sum ← 0
3: resp ← 0
4: for i ← 0 to n − 1 do
5: sum ← sum + A[i]
6: resp ← max{sum, A[i], 0}
7: return resp
Nótese que la fórmula (1) no es una formulación de DP válida, ya que no existe una
definición inductiva de S.
X j
i X
S(i, j) = max { A[x, y]}
k∈[0,i]
l∈[0,j] y=k x=l
Cada valor de S(i, j) representa una solución parcial, la cual es valor máximo entre las
sumas obtenidas para cada valor de k y de l. Cada sumatoria representa la suma de la
siguiente submatriz:
akl . . . akj
Ak,j,i,j = ... .. ..
. .
ail ... aij
Esta solución tiene un costo de O(n4 ). Sin embargo, existe una variación del algoritmo
de Kadane que se encuentra en O(n3 ).
1: procedure Max-Submatrix(A)
2: max ← 0
3: sum ← 0
4: for lef t ← 0 to n − 1 do
5: S←0
6: for right ← lef t to n − 1 do
7: for i ← 0 to n − 1 do
8: S[i] ← M [i, right]
9: sum ← Max-Subarray(S)
10: if sum > max then
11: max ← sum
12: return max
1 2 8 3 9 6 4 5 7
La siguiente formulación DP calcula la longitud del LIS cuyo último elemento se encuentre
en la posición i, y el mayor entre estos valores tendrá que ser la solución global. Esta solución
se encuentra en O(n2 ).
2
LIS(i) = 1 + max {LIS(j)}
j<i
A[j]<A[i]
Existen dos variedades del problema: una que admite elementos repetidos y otra que
no. En el primer caso, la solución óptima es {1, 0, 0, 2} y tiene un valor total de 48. En el
segundo, la solución optima es {1, 0, 1, 0} y tiene un valor de 46.
K(0) = 0
K(w) = max {K(w − wi ) + vi }
i∈[1,n]
Para calcular K(w) se debe agregar un item a otra solución anterior, es decir se debe
agregar vi a K(w − wi ) donde i representa el ı́ndice del item que fue agregado. Para que la
solución sea optima se elige el valor de i que maximize el valor de K(w). El costo de este
algoritmo se encuentra en O(nW ) ya que hay que iterar por cada uno de los n items y se
deben almacenar un número de soluciones parciales proporcial a W . En ambos casos, la
suma de los pesos puede ser menor a W .
3
K(0, 0) = 0
K(w, j) = max{K(w − wj , j − 1) + vj , K(w, j − 1)}
Al calcular K(w, j) el algoritmo debe decidir si debe incluir el item j o no. Si este se
incluye se suma vj a K(w − wj , j − 1), y si no se toma el valor anterior de K(w, j − 1). En
ambos casos el item j solo se considera una vez. Al igual que con la versión con repetición,
el costo del algoritmo se encuentra en O(nW ) y el resultado óptimo corresponde a K(W, n).
4 Subset Sum
Dado un entero t y un conjunto finito de enteros A = {a1 , a2 , . . . an }, determinar si
existe un subconjunto S ⊆ A tal que la suma de todos los enteros en S sea igual a t (más
formalmente ΣS = t).
El siguiente planteamiento DP define una función Q(i, s) que determina si hay un sub-
conjunto no vacı́o dentro de a1 , . . . ai que suma s. Esta función puede tomar un valor de
verdadero o falso (frecuentemente representados como 1 o 0), los cuales representan la
existencia o no de tal subconjunto.
Q(1, s) = (s ≡ a1 )
Q(i, s) = Q(i − 1, s) ∨ Q(i − 1, s − ai )
En el caso base existe un solo subconjunto posible que contiene a1 , por lo que la funcion
se vuelve verdadera si y solo si s = a1 . Para los otros casos, Q(i−1, s) representa que ai ∈
/S
y Q(i − 1, s − ai ) representa que ai ∈ S, por lo que si uno de estos casos resulta verdadero
entones Q(i, s) tambien es verdadero. La complejidad del algoritmo es de O(nt).
5 Cambio
Dado un valor V y una lista de denominaciones de n monedas M = {m1 , m2 , . . . mn },
determinar el número mı́nimo de monedas que deben usarse para obtener V .
Por ejemplo, para V = 10, n = 2 y M = {1, 5} existen tres conjuntos de monedas, donde
el número mı́nimo es 2.
10 × (1) (a)
5 × (1) + 1 × (5) (b)
2 × (5) (c)
4
En el siguiente planteamiento, C(v) representa el número mı́nimo de monedas para
obtener v. A cada paso, el algoritmo itera a través de cada moneda y busca una solución
optima que corresponda a v − mi . El caso base ocurre cuando v = 0, y si no existe una
solución entoces el número de monedas es infinito. El algoritmo tiene un costo de O(nv).
C(v < 0) = ∞
C(0) = 0
C(v) = 1 + min {C(v − mi )}
i∈[1,n]
Este problema puede ser descrito mediante un grafo, donde las ciudades son vértices y las
distancias son aristas. Cada solución posible consiste en una permutación de n ciudades,
ası́ que un algoritmo de fuerza bruta que compare cada permutación estará en O(n!).
Para realizar una formulación DP hay que observar que cada segmento continuo del
camino más corto recorre esos vértices de la manera más corta posible. Dados un sub-
conjunto S ⊆ {v2 , . . . vn } y un vértice j ∈ S, la función D(S, j) representa la longitud del
camino más corto desde 1 hasta j que visite todos los vértices en S una vez y no visite
ningún otro (el vértice de salida no cuenta).
C(∅, 1) = 0
C(S, j) = min{C(S − {j}, i) + dij }
i∈S
i6=j
El caso base es aquel en donde S esta vacı́o y el vértice de destino es 1. De caso contrario,
para hallar C(S, j) se elige un vértice penúltimo i tal que la longitud del camino de 1 hasta
i más la distancia entre i y j sea mı́nima. Para hallar el resultado final se debe calcular
C(V, 1) de la misma manera, el cual es el único caso donde el recorrido puede terminar en
1 además del caso base.
1: procedure TSP-Shortest(S)
2: C({}, 1) ← 0
3: for s ← 1 to n − 1 do
4: for all S ⊆ {2, . . . n}, |S| = s do
5: for all j ∈ S do
6: C(S, j) ← mini∈S−{j} {C(S − {j}, i) + dij }
7: return min2≤j≤n {C({2, . . . , n}, j) + dj1 }
5
Este algoritmo se conoce como el algoritmo Held-Karp y tiene un costo temporal O(n2 2n ).
7 Distancia de Edición
Dadas dos cadenas x = x1 . . . xn y y = y1 . . . ym , la distancia de edición E entre x e y se
define como el número mı́nimo de inserciones, borrados o sustituciones para transformar x
en y.
La idea de DP para calcular la distancia de edición es comparando prefijos de x e y de
derecha a izquierda. Consideremos los prefijos x1 . . . xi e y1 . . . yj . Denotamos por E(i, j)
como la distancia de edición entre x1 . . . xi e y1 . . . yj . Aquı́ tenemos dos casos para analizar.
(2) Si xi 6= yj , entonces tenemos tres opciones: insertamos un caracter en x para que sea
igual a yj , borramos xi , o sustituimos xi por yj .
(a) Insertar un caracter en x1 . . . xi−1 . El caracter que se inserta debe ser igual a yj .
Esto hace que x1 . . . xi xi+1 , con xi+1 = yj y entonces los ultimos caracteres de ambos
prefijos coinciden. Por lo tanto, nos queda verificar recursivamente la distancia de
edición entre x1 . . . xi e y1 . . . yj−1 . Tenemos entonces que E(i, j) = 1 + E(i, j − 1).
En el caso (2) ¿cómo sabemos cual operación hacer? No lo podemos saber, y por lo tanto,
debemos de probar las tres operaciones y elegir la más barata. Entonces la formulación DP
para la distancia de edición es
1 + E(i, j − 1)
E(i, j) = min 1 + E(i − 1, j)
δij + E(i − 1, j − 1)