Algoritmo clásico de programación dinámica (secuencia de Fibonacci)

Escena aplicable:

Los subproblemas son de la misma naturaleza que el problema original.

Los subproblemas están interrelacionados (diferente del algoritmo divide y vencerás)

Buscando la solución óptima, el núcleo es exhaustivo

Funciones de planificación dinámica:

  1. Subproblemas superpuestos
  2. Ecuación de transición de estado (la más crítica)
  3. Subestructura óptima

Marco de resolución de problemas de programas dinámicos

  1. caso base
  2. Estado exhaustivo
  3. Transición de estado

Caso clásico 1: secuencia de Fibonacci

f [1] = 1
f [2] = 2
f [n] = f [n-1] + f [n-2] // ecuación de transición de estado

La secuencia numérica de Fibonacci no es un auténtico problema de programación dinámica, al menos no es un problema de búsqueda de una solución óptima.

Implementación de código-recursividad (recursividad violenta)

/*
    斐波那契数列
    暴力递归
*/
#include <stdio.h>
#include <stdlib.h>

int fib(int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 递归调用
    return fib(n - 1) + fib(n - 2);
}

int main() {
    int n = 200;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

El método de recursividad es demasiado ineficaz. Hay muchos cálculos repetitivos, la complejidad del tiempo es O (2 ^ n) y lleva mucho tiempo.

Método recursivo de implementación de código (de arriba hacia abajo / con memo)

Recurra primero de arriba a abajo y luego retroceda de abajo hacia arriba.

/*
    斐波那契数列
    带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int helper(int *memo, int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 备忘录查询
    if (memo[n] != 0) return memo[n];

    memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
    return memo[n];
}

int fib(int n) {
    // 备忘录初始化
    int *memo = new int[n + 1];
    memset(memo, 0, n+1);
    // 进行带备忘录的递归
    return helper(memo, n);
}

int main() {
    int n = 50;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

Ahora, cada nodo solo se calcula una vez, por lo que la complejidad del tiempo es O (n).
Debido a una nueva asignación de memoria adicional. Entonces, hay un gasto de espacio más, por lo que la complejidad del espacio es O (n).
La solución recursiva con memo es espacio para el tiempo.

Método iterativo de implementación de código (de abajo hacia arriba)

/*
    斐波那契数列
    带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int helper(int *memo, int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 备忘录查询
    if (memo[n] != 0) return memo[n];

    memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
    return memo[n];
}

int fib(int n) {
    // 备忘录初始化
    int *memo = new int[n + 1];
    memset(memo, 0, n+1);
    // 进行带备忘录的递归
    return helper(memo, n);
}

int main() {
    int n = 50;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_44937328/article/details/115344896
Recomendado
Clasificación