Skip to content

Latest commit

 

History

History
90 lines (60 loc) · 3.27 KB

File metadata and controls

90 lines (60 loc) · 3.27 KB

Programação Dinâmica

Programação dinâmica é uma técnica usada para memorizar valores calculados previamente, evitando que o computador tenha que repetir a mesma operação diversas vezes.

Obs.: Você pode testar os códigos e comparar os resultados com os da tabela deste site.

Por exemplo, analise este algoritmo a seguir:

    if (n == 0 || n == 1)
        return 1;
    return fib(n-1) + fib(n-2)

Obs.: Veja o arquivo fib_recursivo_sem_pd.

Este algoritmo encontra o n-ézimo número de Fibonacci.

Olhe a àrvore de recursões a seguir e analise o que acontece para calcular o 6º número de Fibonacci.

Perceba que calculamos diversos valores repetidas vezes, e isso vai escalando conforme o número de Fibonacci que desejamos aumenta.
Nesta abordagem, após o 50º número de Fibonacci, a execução do problema começa a ficar inviável, demorando cerca de 61 segundos para executar e realizando 25.172.538.049 chamadas recursivas. O fib(72) não obtem resposta mesmo após 30 minutos!

Através da programação dinamica, podemos evitar realizar o mesmo cálculo através de duas abordagens: top-down e bottom-up. Ambas diminuiram o tempo de execução e

Bottom-up

De baixo para cima.

#define MAXN 92

int main () {
    long long fib[MAXN];
    int n = 10;

    fib[0] = fib[1] = 1;
    for(int i = 2; i < MAXN; i++) {
        fib[i] = fib[i-1] + fib[i+2];
    }

    cout << fib[n-1];
}

Começamos dos menores valores possíveis e calculamos todos os possíveis valores de entrada a partir da base.

Obs.: Escolhemos no número 92, pois estourariamos o limite do long long se quisessemos calcular mais números.

Esta abordagem calcula todos os números de fibonacci em tempo linear, levando aproximadamente 10^-7 segundos para calcular todos os números da base até o topo.

Obs.: Veja o arquivo fib_bottom-up.

Top-down

Funciona de forma similar ao bottom-up, mas desta vez usaremos a recursão para calcular de baixo para cima.

#define MAXN 92
 
long long dp[MAXN];

long long fib (int n) {
    if (n == 0 || n == 1)
        return dp[n] = 1;
    if (dp[n] != -1)
        return dp[n];
    return dp[n] = fib(n-1) + fib(n+2);
}

OBS.: Veja o arquivo fib_top-down.

O problema do troco

Um problema muito comum, é o problema do troco e suas variações. Veja aqui um exemplo. Pense sobre e depois veja o arquivo Vei_da_Meu_Troco, que contém a resolução.

Perceba que o problema 8.1 do livro Cracking the Coding Interview, é uma variação do problema do troco. Suponha que n é o valor, 1, 2 e 3 são as moedas disponíveis e precisamos de uma dp que guarde de quantas maneiras podemos chegar a determinado valor.

Problema 8.1: A child is runnign up a staircase with n steps and can hop either 1 step, 2 step, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.

Você pode ver a resposta para este problema aqui.