Módulo 2 · Matemática discreta e combinatória

Recorrências

Aula 2.3 · cerca de 20 minutos

Uma recorrência define uma sequência em termos dos termos anteriores. Toda função recursiva gera uma recorrência para o seu custo, e resolvê-la dá a complexidade.

Fibonacci

F(0) = 0,  F(1) = 1,  F(n) = F(n−1) + F(n−2)

Recorrências lineares homogêneas se resolvem pela equação característica. Aqui ela é x² = x + 1, com raízes φ = (1+√5)/2 ≈ 1,618 e ψ = (1−√5)/2. Daí sai a fórmula de Binet:

F(n) = (φⁿ − ψⁿ) / √5

A versão recursiva ingênua faz cerca de φⁿ chamadas, ou seja, crescimento exponencial. Com memoização passa a ser O(n). Com exponenciação de matrizes, O(log n).

from functools import cache

@cache
def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)

def fib_matriz(n):
    # [[1,1],[1,0]]^n = [[F(n+1), F(n)], [F(n), F(n-1)]]
    def mul(a, b):
        return [[a[0][0]*b[0][0] + a[0][1]*b[1][0], a[0][0]*b[0][1] + a[0][1]*b[1][1]],
                [a[1][0]*b[0][0] + a[1][1]*b[1][0], a[1][0]*b[0][1] + a[1][1]*b[1][1]]]
    r, m = [[1, 0], [0, 1]], [[1, 1], [1, 0]]
    while n:
        if n & 1:
            r = mul(r, m)
        m = mul(m, m)
        n >>= 1
    return r[0][1]
Dica: Programação dinâmica é, basicamente, avaliar uma recorrência na ordem certa guardando os resultados.

Exercício 1

Resolva T(n) = 2T(n−1) + 1 com T(0) = 0 (Torre de Hanói).

Exercício 2

De quantas formas se sobe uma escada de n degraus dando passos de 1 ou 2?