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 para la DP de rangos estándar a .
Condiciones
La aceleración se aplica a transiciones de la forma
De forma similar a la DP de divide y vencerás, sea el valor máximo de que minimiza la expresión de la transición ( se denomina el «punto de corte óptimo» más adelante en este artículo). La optimización requiere que se cumpla lo siguiente:
Podemos mostrar que esto vale cuando la función de costo satisface las siguientes condiciones para :
-
;
-
(la desigualdad del cuadrángulo [QI]).
Este resultado se demuestra más abajo.
Algoritmo
Procesemos los estados de la DP de modo que calculemos y antes que , y al hacerlo también calculemos y . Entonces, para calcular , en lugar de probar valores de desde hasta , solo hay que probar desde hasta . Para procesar los pares en este orden basta con usar bucles for anidados en los que va del valor máximo al mínimo y va de 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:
Como se ve, la mayoría de los términos de esta expresión se cancelan entre sí, salvo los términos positivos con y los términos negativos con . Así, toda la suma se puede estimar como
en lugar de , 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 es simplemente la suma de los elementos del subarreglo 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 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 , basta con demostrar que
asumiendo que se cumplen las condiciones dadas.
Lema
Demostración
-
La desigualdad se reduce a (esto asume que para todo , lo cual vale en todos los problemas que usan esta optimización). Sea .-
Si ,
Nótese quePor lo tanto,
Por la hipótesis inductiva, . Además, se da que . Combinar estos 2 hechos con la desigualdad de arriba produce el resultado deseado.
-
Si , la demostración de este caso es simétrica al caso anterior.
-
-
Sean y .-
Si ,
donde
Usar la QI sobre y sobre el estado de la DP para los índices (por la hipótesis inductiva) produce el resultado deseado.
-
Si , 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 . Definimos .
Supongamos que mostramos que
Tomando , por definición, . Por lo tanto, aplicando la desigualdad a todos los , podemos inferir que es al menos tan grande como , lo que demuestra la primera mitad de la desigualdad.
Ahora, usando la QI sobre algunos índices , obtenemos
\leq& (dp(i, q) + dp(q+1, j-1) + C(i, j-1)) + (dp(i, p) + dp(p+1, j) + C(i, j)) \
\implies& dp_{p}(i, j-1) + dp_{q}(i, j) ≤ dp_{p}(i, j) + dp_{q}(i, j-1) \
\implies& dp_{p}(i, j-1) - dp_{q}(i, j-1) ≤ dp_{p}(i, j) - dp_{q}(i, j) \
\end{align}
Finalmente,
Esto demuestra la primera parte de la desigualdad, es decir, . La segunda parte se puede mostrar con la misma idea, partiendo de la desigualdad .
Esto completa la demostración.