Letra del problema
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Soluciones
Método 1 - Verificar paridad para cada $F_x$
Un numero $x$ es par si es divisible por 2, esto es decir que $x$ es múltiplo de 2. Más formalmente:
Por esto, $\frac x2 = c$ con resto 0, lo cual puede verificarse mediante aritmética modular: $x \bmod 2 = 0$
Sea $F_x$ la sucesión de Fibonacci, esta es generada por la recurrencia:
Esta recurrencia se puede implementar naturalmente de manera recursiva, aunque resulte ineficiente. Normalmente las condiciones iniciales elegidas son $(0, 1)$, o $(1, 1)$ pero esto no cambia el resultado para el problema en cuestión donde solo interesa sumar términos pares de la sucesión.
Entonces una solución posible es sumar cada $F_x$ tal que $F_x \leq n$ y $F_x \bmod 2 = 0$.
\begin{algorithm}\caption{}\begin{algorithmic}
\FUNCTION{pe2}{$n$}
\STATE $i := 0$
\STATE $x := 0$
\STATE $r := 0$
\WHILE{$x \leq n$}
\IF{$x \; mod \; 2 = 0$}
\STATE $r := r + x$
\ENDIF
\STATE $i := i + 1$
\STATE $x := $ \CALL{fib}{$i$}
\ENDWHILE
\RETURN $r$
\ENDFUNCTION
\STATE
\FUNCTION{fib}{$x$}
\IF{$x = 0$}
\RETURN $0$
\ENDIF
\IF{$x = 1$}
\RETURN $1$
\ENDIF
\RETURN \CALL{fib}{$x-1$} $ + $ \CALL{fib}{$x-2$}
\ENDFUNCTION
\end{algorithmic}\end{algorithm}
Complejidad
Sea $x(n)$ la función inversa de $F_x=n$, esta retorna en que posición de la sucesión se
encuentra el valor $n$:
El ciclo while en $\text{PE2}(n)$ se ejecuta una cantidad de veces no mayor a $O(\log(n))$. Por otro lado, $\text{FIB}(x) \in O(2^n)$.
Por lo tanto, $\text{PE2}(n) \in O(2^n \log(n))$.
Método 2 - Generar $F_x$ verificando paridad de términos
Es natural implementar $F_x$ recursivamente, porque de acuerdo al paso recursivo cada término depende de los dos términos anteriores en la sucesión:
Si la recurrencia se cumple para $x$, entonces también se cumple para $x+2$. Luego:
Esta observación permite generar la sucesión “hacia adelante”, sin tener que ir “hacia atras”, y se puede implementar por recursión de cola o de manera iterativa.
La versión iterativa de $\text{FIB}$:
\begin{algorithm}\begin{algorithmic}
\FUNCTION{fib}{$x$}
\STATE $a := 0$
\STATE $b := 1$
\FOR{$j := 0$ \TO $x-1$}
\STATE $t := a + b$
\STATE $a := b$
\STATE $b := t$
\ENDFOR
\RETURN $b$
\ENDFUNCTION
\end{algorithmic}\end{algorithm}
Con dos variables es suficiente para guardar los dos últimos valores generados, y con estos generar el siguiente.
Esta versión de $\text{FIB}(x)$, además de ser más eficiente, se puede adaptar fácilmente para resolver el problema en cuestión donde hay que sumar cada $F_x$ tal que $F_x \leq n$ y $F_x \bmod 2 = 0$ , y no es necesario usar una función auxiliar para calcular $F_x$.
\begin{algorithm}\caption{}\begin{algorithmic}
\FUNCTION{pe2}{$n$}
\STATE $a := 0$
\STATE $b := 1$
\STATE $r := 0$
\WHILE{$b \leq n$}
\IF{$x \; mod \; 2 = 0$}
\STATE $r := r + b$
\ENDIF
\STATE $t := a + b$
\STATE $a := b$
\STATE $b := t$
\ENDWHILE
\RETURN $r$
\ENDFUNCTION
\end{algorithmic}\end{algorithm}
Complejidad
Sea $x(n)$ la función inversa de $F_x=n$, esta retorna en que posición de la sucesión se
encuentra el valor $n$:
El ciclo while en $\text{PE2}(n)$ se ejecuta una cantidad de veces no mayor a $O(\log(n))$.
Por lo tanto, $\text{PE2}(n) \in O(\log(n))$.
Método 3 - Generar términos pares de $F_x$
Observando los términos de $F_x$ comenzando desde $(1, 1)$:
Se puede notar que cualquier término par siempre se encuentra en una posición que es múltiplo de 3.
Mantener tres variables para guardar los tres últimos valores generados de $F_x$ sirve para evitar tener que verificar la paridad de cada termino, ya que en toda iteración el tercer término generado es siempre par.
\begin{algorithm}\caption{}\begin{algorithmic}
\FUNCTION{pe2}{$n$}
\STATE $a := 1$
\STATE $b := 1$
\STATE $c := 2$
\STATE $r := 0$
\WHILE{$c \leq n$}
\STATE $r := r + c$
\STATE $a := b + c$
\STATE $b := a + c$
\STATE $c := a + b$
\ENDWHILE
\RETURN $r$
\ENDFUNCTION
\end{algorithmic}\end{algorithm}
Complejidad
$\text{PE2}(n) \in O(\log(n))$.
Método 4 - Suma de pares en forma cerrada
Partiendo de la suma de $F_x$:
Reagrupando los términos de \ref{eq4.1}:
\begin{algorithm}\caption{}\begin{algorithmic}
\STATE $\phi = (1 + \sqrt{5})/2$
\STATE
\FUNCTION{pe2}{$n$}
\STATE $x := \log_\phi(n \times \sqrt{5} + 0.5)$
\STATE $x := $ \CALL{nearestMultOf3}{$x$}
\RETURN $($\CALL{fib}{$x+2$} $-1)/2$
\ENDFUNCTION
\STATE
\FUNCTION{fib}{$x$}
\RETURN $(\phi^x -(1-\phi)^x)/\sqrt{5}$
\ENDFUNCTION
\STATE
\FUNCTION{nearestMultOf3}{$x$}
\RETURN $3 \times (x/3)$
\ENDFUNCTION
\end{algorithmic}\end{algorithm}