五大常用算法——动态规划

基本概念:
  动态规划过程:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
基本思想
  类似于分治算法(后续博客介绍),将一个待求解的问题分解成若干个子问题,顺序求解每个子问题,前一个子问题的解包含后一个子问题有用的信息。求解每一个子问题的最优解,则最后一个子问题的解就是初始问题的解。
  动态规划问题求解过程中会出现子问题重叠的问题(就是重复计算子问题),我们可以利用一个二维数组将每一个子问题的解记录下来,这样就减少了计算次数。动态规划算法的核心是记住已经求过的解,记住求解的方式有两种:①自顶向下的备忘录法自底向上
  比如我们熟悉的斐波拉契数列问题:指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)
  五大常用算法——动态规划_第1张图片
  递归树中的每一个子节点都会执行一次,很多重复的节点被执行,fib(2)被重复执行了5次。由于调用每一个函数的时候都要保留上下文,所以空间上开销也不小。这么多的子节点被重复执行,如果在执行的时候把执行过的子节点保存起来,后面要用到的时候直接查表调用的话可以节约大量的时间。
  (1)自顶向下的备忘录

public class Fibonacci {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m[] = new int[n + 1];
        for(int i =0;i <= n; i++){
            m[i] = -1;
        }
        System.out.println(fib(n, m));
    }
    public static int fib(int n, int[] m){
        if(m[n] != -1){
            return m[n];
        }
        if(n <= 2){
            m[n] = 1;
        }else{
            m[n] = fib(n - 1, m) + fib(n - 2, m);
        }
        return m[n];
    }
}

(2)自底向上

 public static int fib1(int n){
        if(n <= 1) {
            return n;
        }
        int m_i_2 = 0;
        int m_i_1 = 1;
        int m_i = 1;
        for(int i = 2; i <= n; i++){
            m_i = m_i_1 + m_i_2;
            m_i_1 = m_i;
            m_i_2 = m_i_1;
        }
        return m_i;
    }

动态规划问题的性质:
  (1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
  (2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
 (3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。
求解步骤:
(1)分析最优解的性质,并刻画其结构特征。
(2)递归的定义最优解。
(3)以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值
(4)根据计算最优值时得到的信息,构造问题的最优解

你可能感兴趣的:(算法)