Skip to Content

Optimización de Knuth

La optimización de Knuth, también conocida como aceleración de Knuth-Yao, es un caso especial de programación dinámica sobre rangos, que puede optimizar la complejidad temporal de las soluciones en un factor lineal, de O(n3)O(n^3) para la DP de rangos estándar a O(n2)O(n^2).

Condiciones

La aceleración se aplica a transiciones de la forma

dp(i,j)=minik<j[dp(i,k)+dp(k+1,j)+C(i,j)].dp(i, j) = \min_{i \leq k < j} [ dp(i, k) + dp(k+1, j) + C(i, j) ].

De forma similar a la DP de divide y vencerás, sea opt(i,j)opt(i, j) el valor máximo de kk que minimiza la expresión de la transición (optopt se denomina el «punto de corte óptimo» más adelante en este artículo). La optimización requiere que se cumpla lo siguiente:

opt(i,j1)opt(i,j)opt(i+1,j).opt(i, j-1) \leq opt(i, j) \leq opt(i+1, j).

Podemos mostrar que esto vale cuando la función de costo CC satisface las siguientes condiciones para abcda \leq b \leq c \leq d:

  1. C(b,c)C(a,d)C(b, c) \leq C(a, d);

  2. C(a,c)+C(b,d)C(a,d)+C(b,c)C(a, c) + C(b, d) \leq C(a, d) + C(b, c) (la desigualdad del cuadrángulo [QI]).

Este resultado se demuestra más abajo.

Algoritmo

Procesemos los estados de la DP de modo que calculemos dp(i,j1)dp(i, j-1) y dp(i+1,j)dp(i+1, j) antes que dp(i,j)dp(i, j), y al hacerlo también calculemos opt(i,j1)opt(i, j-1) y opt(i+1,j)opt(i+1, j). Entonces, para calcular opt(i,j)opt(i, j), en lugar de probar valores de kk desde ii hasta j1j-1, solo hay que probar desde opt(i,j1)opt(i, j-1) hasta opt(i+1,j)opt(i+1, j). Para procesar los pares (i,j)(i,j) en este orden basta con usar bucles for anidados en los que ii va del valor máximo al mínimo y jj va de i+1i+1 al valor máximo.

Implementación genérica

Aunque la implementación varía, aquí hay un ejemplo bastante genérico. La estructura del código es casi idéntica a la de la DP de rangos.

int solve() { int N; ... // leer N y la entrada int dp[N][N], opt[N][N]; auto C = [&](int i, int j) { ... // Implementar la función de costo C. }; for (int i = 0; i < N; i++) { opt[i][i] = i; ... // Inicializar dp[i][i] según el problema } for (int i = N-2; i >= 0; i--) { for (int j = i+1; j < N; j++) { int mn = INT_MAX; int cost = C(i, j); for (int k = opt[i][j-1]; k <= min(j-1, opt[i+1][j]); k++) { if (mn >= dp[i][k] + dp[k+1][j] + cost) { opt[i][j] = k; mn = dp[i][k] + dp[k+1][j] + cost; } } dp[i][j] = mn; } } return dp[0][N-1]; }

Complejidad

La complejidad del algoritmo se puede estimar como la siguiente suma:

i=1Nj=i+1N[opt(i+1,j)opt(i,j1)]=i=1Nj=iN1[opt(i+1,j+1)opt(i,j)]. \sum\limits_{i=1}^N \sum\limits_{j=i+1}^N [opt(i+1,j)-opt(i,j-1)] = \sum\limits_{i=1}^N \sum\limits_{j=i}^{N-1} [opt(i+1,j+1)-opt(i,j)].

Como se ve, la mayoría de los términos de esta expresión se cancelan entre sí, salvo los términos positivos con j=N1j=N-1 y los términos negativos con i=1i=1. Así, toda la suma se puede estimar como

k=1N[opt(k,N)opt(1,k)]=O(n2), \sum\limits_{k=1}^N[opt(k,N)-opt(1,k)] = O(n^2),

en lugar de O(n3)O(n^3), como sería si usáramos una DP de rangos habitual.

En la práctica

La aplicación más común de la optimización de Knuth es en la DP de rangos, con la transición dada. La única dificultad está en demostrar que la función de costo satisface las condiciones dadas. El caso más simple es cuando la función de costo C(i,j)C(i, j) es simplemente la suma de los elementos del subarreglo S[i,i+1,...,j]S[i, i+1, …, j] para algún arreglo (según el enunciado). Sin embargo, a veces pueden ser más complicadas.

Nótese que, más que las condiciones sobre la transición de la DP y la función de costo, la clave de esta optimización es la desigualdad sobre el punto de corte óptimo. En algunos problemas, como el del árbol binario de búsqueda óptimo (que es, de hecho, el problema original para el que se desarrolló esta optimización), las transiciones y las funciones de costo serán menos evidentes; no obstante, aún se puede demostrar que opt(i,j1)opt(i,j)opt(i+1,j)opt(i, j-1) \leq opt(i, j) \leq opt(i+1, j) y, por lo tanto, usar esta optimización.

Demostración de corrección

Para demostrar la corrección de este algoritmo en términos de las condiciones sobre C(i,j)C(i,j), basta con demostrar que

opt(i,j1)opt(i,j)opt(i+1,j) opt(i, j-1) \leq opt(i, j) \leq opt(i+1, j)

asumiendo que se cumplen las condiciones dadas.

Lema

dp(i,j)dp(i, j) también satisface la desigualdad del cuadrángulo, dadas las condiciones del problema.

Demostración

La demostración de este lema usa inducción fuerte. Se tomó del artículo Efficient Dynamic Programming Using Quadrangle Inequalities , de F. Frances Yao, que introdujo la aceleración de Knuth-Yao (este enunciado en particular es el Lema 2.1 del artículo). La idea es inducir sobre la longitud l=dal = d - a. El caso l=1l = 1 es trivial. Para l>1l > 1 consideramos 2 casos:
  1. b=cb = c
    La desigualdad se reduce a dp(a,b)+dp(b,d)dp(a,d)dp(a, b) + dp(b, d) \leq dp(a, d) (esto asume que dp(i,i)=0dp(i, i) = 0 para todo ii, lo cual vale en todos los problemas que usan esta optimización). Sea opt(a,d)=zopt(a,d) = z.

    • Si z<jz < j,
      Nótese que

      dp(a,b)dpz(a,b)=dp(a,z)+dp(z+1,b)+C(a,b). dp(a, b) \leq dp_{z}(a, b) = dp(a, z) + dp(z+1, b) + C(a, b).

      Por lo tanto,

      dp(a,b)+dp(b,d)dp(a,z)+dp(z+1,b)+dp(b,d)+C(a,b) dp(a, b) + dp(b, d) \leq dp(a, z) + dp(z+1, b) + dp(b, d) + C(a, b)

      Por la hipótesis inductiva, dp(z+1,b)+dp(b,d)dp(z+1,d)dp(z+1, b) + dp(b, d) \leq dp(z+1, d). Además, se da que C(a,b)C(a,d)C(a, b) \leq C(a, d). Combinar estos 2 hechos con la desigualdad de arriba produce el resultado deseado.

    • Si zjz \geq j, la demostración de este caso es simétrica al caso anterior.

  2. b<cb < c
    Sean opt(b,c)=zopt(b, c) = z y opt(a,d)=yopt(a, d) = y.

    • Si zyz \leq y,

      dp(a,c)+dp(b,d)dpz(a,c)+dpy(b,d) dp(a, c) + dp(b, d) \leq dp_{z}(a, c) + dp_{y}(b, d)

      donde

      dpz(a,c)+dpy(b,d)=C(a,c)+C(b,d)+dp(a,z)+dp(z+1,c)+dp(b,y)+dp(y+1,d). dp_{z}(a, c) + dp_{y}(b, d) = C(a, c) + C(b, d) + dp(a, z) + dp(z+1, c) + dp(b, y) + dp(y+1, d).

      Usar la QI sobre CC y sobre el estado de la DP para los índices z+1y+1cdz+1 \leq y+1 \leq c \leq d (por la hipótesis inductiva) produce el resultado deseado.

    • Si z>yz > y, la demostración de este caso es simétrica al caso anterior.

Esto completa la demostración del lema.

Ahora, consideremos el siguiente planteo. Tenemos 2 índices ipq<ji \leq p \leq q < j. Definimos dpk=C(i,j)+dp(i,k)+dp(k+1,j)dp_{k} = C(i, j) + dp(i, k) + dp(k+1, j).

Supongamos que mostramos que

dpp(i,j1)dpq(i,j1)    dpp(i,j)dpq(i,j). dp_{p}(i, j-1) \geq dp_{q}(i, j-1) \implies dp_{p}(i, j) \geq dp_{q}(i, j).

Tomando q=opt(i,j1)q = opt(i, j-1), por definición, dpp(i,j1)dpq(i,j1)dp_{p}(i, j-1) \geq dp_{q}(i, j-1). Por lo tanto, aplicando la desigualdad a todos los ipqi \leq p \leq q, podemos inferir que opt(i,j)opt(i, j) es al menos tan grande como opt(i,j1)opt(i, j-1), lo que demuestra la primera mitad de la desigualdad.

Ahora, usando la QI sobre algunos índices p+1q+1j1jp+1 \leq q+1 \leq j-1 \leq j, obtenemos

dp(p+1,j1)+dp(q+1,j)dp(q+1,j1)+dp(p+1,j)    (dp(i,p)+dp(p+1,j1)+C(i,j1))+(dp(i,q)+dp(q+1,j)+C(i,j))(dp(i,q)+dp(q+1,j1)+C(i,j1))+(dp(i,p)+dp(p+1,j)+C(i,j))    dpp(i,j1)+dpq(i,j)dpp(i,j)+dpq(i,j1)    dpp(i,j1)dpq(i,j1)dpp(i,j)dpq(i,j)amp;dp(p+1,j1)+dp(q+1,j)dp(q+1,j1)+dp(p+1,j)    amp;(dp(i,p)+dp(p+1,j1)+C(i,j1))+(dp(i,q)+dp(q+1,j)+C(i,j))amp;(dp(i,q)+dp(q+1,j1)+C(i,j1))+(dp(i,p)+dp(p+1,j)+C(i,j))    amp;dpp(i,j1)+dpq(i,j)dpp(i,j)+dpq(i,j1)    amp;dpp(i,j1)dpq(i,j1)dpp(i,j)dpq(i,j)\begin{align} &amp;dp(p+1, j-1) + dp(q+1, j) ≤ dp(q+1, j-1) + dp(p+1, j) \ \implies&amp; (dp(i, p) + dp(p+1, j-1) + C(i, j-1)) + (dp(i, q) + dp(q+1, j) + C(i, j)) \
\leq&amp; (dp(i, q) + dp(q+1, j-1) + C(i, j-1)) + (dp(i, p) + dp(p+1, j) + C(i, j)) \
\implies&amp; dp_{p}(i, j-1) + dp_{q}(i, j) ≤ dp_{p}(i, j) + dp_{q}(i, j-1) \ \implies&amp; dp_{p}(i, j-1) - dp_{q}(i, j-1) ≤ dp_{p}(i, j) - dp_{q}(i, j) \ \end{align}

Finalmente,

dpp(i,j1)dpq(i,j1)    0dpp(i,j1)dpq(i,j1)dpp(i,j)dpq(i,j)    dpp(i,j)dpq(i,j)amp;dpp(i,j1)dpq(i,j1)amp;    0dpp(i,j1)dpq(i,j1)dpp(i,j)dpq(i,j)amp;    dpp(i,j)dpq(i,j)\begin{align} &amp;dp_{p}(i, j-1) \geq dp_{q}(i, j-1) \ &amp;\implies 0 \leq dp_{p}(i, j-1) - dp_{q}(i, j-1) \leq dp_{p}(i, j) - dp_{q}(i, j) \ &amp;\implies dp_{p}(i, j) \geq dp_{q}(i, j) \end{align}

Esto demuestra la primera parte de la desigualdad, es decir, opt(i,j1)opt(i,j)opt(i, j-1) \leq opt(i, j). La segunda parte opt(i,j)opt(i+1,j)opt(i, j) \leq opt(i+1, j) se puede mostrar con la misma idea, partiendo de la desigualdad dp(i,p)+dp(i+1,q)dp(i+1,p)+dp(i,q)dp(i, p) + dp(i+1, q) ≤ dp(i+1, p) + dp(i, q).

Esto completa la demostración.

Problemas de práctica

Referencias