#593 #594 Ya, la verdad es que me explico un poco como el culo.
Vuelvo a intentar explicarlo
Lo de dynamic programming es esto
https://en.wikipedia.org/wiki/Dynamic_programming#Fibonacci_sequence
Es decir, si tu tienes una funcion f(x) que se calcula recursivamente con términos anteriores o posteriores a x lo que puedes hacer es guardar en alguna estructura de datos los valores que ya hayas calculado para f(x) y devolverlos inmediatamente en lugar de emplear la recurrencia.
O sea, si f son los números de Fibonacci entonces f(13) = f(12) + f(11), pero si ya sabemos que f(13) = 144 podríamos expresar f(14) = 144 + f(12) en lugar de f(14) = f(13) + f(12), ahorrándonos un cojón de cálculos. Y si los calculamos crecientemente resulta que eliminamos la recursividad al 100%.
Pues en mi planteamiento f(x) es una función con dos variables
f(i, ac) = 1 si puedo llegar a la última instrucción del programa partiendo de la iésima instrucción, 0 en caso contrario. ac es un número que puede valer 0 o 1 y nos indica si ya hemos cambiado alguna instrucción o no
Entonces, f(i, ac) = max(f(siguiente_i, ac), f(siguiente_i_si_huberamos_modificado_la_instruccion, 1) si ac vale 0 si no 0)
Y usamos la misma idea para reutilizar resultados ya calculados.
f(0, 0) significa entonces "conseguiré llegar a la última instrucción estando ahora en la primera y sin haber cambiado ninguna?", que es de hecho lo que corresponde calcular.
Entonces, el primer f(i, 0) que vale 1 porque f(siguiente_i_si_huberamos_modificado_la_instruccion, 1) vale 1 es justamente la instrucción que hemos modificado en el programa. Sabiendo esa información podemos ejecutar el programa normal, cambiando la instrucción que toca, y calcular el acumulador en otra pasada.
A efectos prácticos estamos iterando sobre una matriz de Nx2 y dedicando un tiempo constante al cada celda de la matriz, por lo que este algoritmo resuelve el problema en tres pasadas al código en lugar de un número cuadrático de ellas.