Estoy viendo Problem thirty one en Project Euler, que pregunta, ¿cuántas formas diferentes hay para hacer £ 2 usando cualquier cantidad de monedas de 1p, 2p, 5p, 10p, 20p, 50p, £ 1 (100p) y £ 2 (200p).Programación dinámica en el paradigma funcional
hay soluciones recursivas, tales como éste en Scala (crédito a Pavel Fatin)
def f(ms: List[Int], n: Int): Int = ms match {
case h :: t =>
if (h > n) 0 else if (n == h) 1 else f(ms, n - h) + f(t, n)
case _ => 0
}
val r = f(List(1, 2, 5, 10, 20, 50, 100, 200), 200)
y aunque corre lo suficientemente rápido, es relativamente ineficaz, llamando a la función f
alrededor de 5,6 millones de veces.
vi solución de otra persona en Java que fue programado dinámicamente (crédito a Wizeman de Portugal)
final static int TOTAL = 200;
public static void main(String[] args) {
int[] coins = {1, 2, 5, 10, 20, 50, 100, 200};
int[] ways = new int[TOTAL + 1];
ways[0] = 1;
for (int coin : coins) {
for (int j = coin; j <= TOTAL; j++) {
ways[j] += ways[j - coin];
}
}
System.out.println("Result: " + ways[TOTAL]);
}
Esto es mucho más eficiente y pasa el bucle interno sólo 1.220 veces.
Si bien obviamente pude traducir esto más o menos al pie de la letra en Scala usando objetos Array
, ¿hay una forma idiomática funcional de hacer esto usando estructuras de datos inmutables, preferiblemente con concisión y rendimiento similares?
He intentado y me he quedado atrapado tratando de actualizar recursivamente un List
antes de decidir que probablemente me estoy acercando al camino equivocado.
Miré a la versión Scala durante 1 minuto y podría decirle cómo funcionaba. Miré el de Java durante 5 minutos, y todavía no sé cómo funciona. Para mí, un buen ejemplo que muestra que funcional no es más complejo que imperativo. – huynhjl
@huynhjl Pero además de mirar un algortihm funcional e impensado, al mismo tiempo está mirando un algoritmo canónico y optimizado. – ziggystar