【算法排序】动态规划

简介: 【算法排序】动态规划

一、动态规划思想

将待求问题划分为若干个子问题,按划分的顺序求解子阶段问题,前一个子问题的解,为后一个子问题的求解提供了有用的信息(最优子结构)。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其它局部解。依次解决各个子问题,最后求出原问题的最优解

二、动态规划与分治法的区别

1、共同点

二者都是求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小的子问题,然后将子问题的解合并,形成原问题的解

2、不同点

1、分治法:将问题分解成子问题后,通常是将子问题的解合并起来得到原问题的解

2、动态规划法:是先解决子问题,将子问题的解保存下来,最后根据子问题的解计算得到原问题的解

三、动态规划特征

1、最优子结构

问题的最优解是由最优子问题的最优解推出的,也就是问题的最优解包含了子问题的最优解

如图:若路线I和J是A到C的最优路径,则根据最优化原理,路线J必是从B到C的最优路线。

反证法证明: 假设有另一路径J是B到C的最优路径,则A到C的路径取I和J比I和J更优,矛盾:从而证明J`必是B到C的最优路径。最优化原理是动态规划的基础,任何问题,如果失去了最优化原理的支持,就不可能用动态规划方法计算哪些问题满足最优化原理

2、重叠子问题

在用递归算法自顶向下解问题时,每次产生的子问题并不是总是新问题。有些子问题被反复计算多次。斐波那契数列问题就存在重叠子问题。在递归实现中,当计算F(n)时,会先计算F(n-1)和F(n-2),而计算F(n-1)时又会先计算F(n-2)和F(n-3),这样就会出现重复计算的情况。

四、动态规划求解问题的基本步骤

动态规划所处理的问题是一个多阶段决策的问题,一般由初始状态开始,通过中间阶段决策的选择,达到结束状态。动态规划算法的代码设计都有一定的模式。一般经过以下几个步骤:

初始状态->决策1->决策2->…->决策n->结束状态

  1. 找出最优解的性质,并刻画其结构特征(找问题状态)
  2. 递归地定义最优值(找状态转移方程)
  3. 自底向上地方式计算最优值
  4. 根据计算最优值时得到的信息,构造最优解

五、斐波那契数分析

斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0, F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

给定 N,计算 F(N)。

序列为:0、1

下标为:2

解释:F(2) = F(N - 1) + F(N - 2)= F(2 - 1) + F(2 - 2)=1+0 = 1

下标2的值为:1

序列为:0、1、1

数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和(示意图如下)

六、实现思路

  1. 定义一个要求的斐波那契数
  2. 判断求的斐波那契数是否小于等于1,是的话直接返回求的斐波那契数,否的话,则创建一个数组,用来记录子问题的解
  3. 初始化第一个斐波那契数值,和第二个斐波那契数值。求第三个斐波那契数值的时候,把前两个下标的值进行相加,得出第三个斐波那契的数值。依次按照这种方式,最终得出需要求的斐波那契数值

七、代码实现

public class Fibonacci {
    public static void main(String[] args) {
        int numberArr = 10; // 求第10个斐波那契数
        int result = fibonacci(numberArr); // 第10个斐波那契数的值
        System.out.println("第10个斐波那契数值为:"+ result); // 输出第10个斐波那契数的值
    }
    /**
    * 斐波那契数列的动态规划算法
    * @paramn  第numberArr个斐波那契数,dp为数据处理后的值
    * @return 第numberArr个斐波那契数的值
    */
    public static int fibonacci(int numberArr) {
        if (numberArr <= 1) {
            // 当numberArr小于等于1时,直接返回numberArr
            return numberArr;
        }
        //创建数组,用于记录子问题的解
        //dp为数据处理后的值
        int[] dp = new int[numberArr + 1];
        dp[0] = 0; // 初始化第一个数
        dp[1] = 1; // 初始化第二个数
        // 递推求解子问题
        for (int i = 2; i <= numberArr; i++) {
            //dp[i]:i为该求下标的值
            //dp[i-1]:i为该求下标-1的值
            //dp{[i-2]:i为该求下标-2的值
            //算出两个下标的值后进行相加,最后得出该求下标的值
            dp[i] = dp[i - 1] + dp[i - 2];
            System.out.println("第"+i+"轮numberArr的值为"+ dp[i]);
        }
        // 返回第numberArr个斐波那契数的值
        return dp[numberArr];
    }
}


相关文章
|
4天前
|
算法
常见的算法排序(2)
常见的算法排序(2)
11 3
|
4天前
|
机器学习/深度学习 存储 算法
数据结构与算法 动态规划(启发式搜索、遗传算法、强化学习待完善)
数据结构与算法 动态规划(启发式搜索、遗传算法、强化学习待完善)
11 1
|
4天前
|
算法 搜索推荐 索引
数据结构与算法 排序(下)
数据结构与算法 排序(下)
10 1
|
4天前
|
缓存 算法 搜索推荐
数据结构与算法 排序(上)
数据结构与算法 排序(上)
9 0
|
5天前
|
算法 调度
【问题探讨】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究
【问题探讨】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究
|
7天前
|
搜索推荐 C语言
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
11 0
|
13天前
|
算法
讲课:拓扑排序、最短路算法
讲课:拓扑排序、最短路算法
|
24天前
|
算法
代码随想录算法训练营第五十六天 | LeetCode 647. 回文子串、516. 最长回文子序列、动态规划总结
代码随想录算法训练营第五十六天 | LeetCode 647. 回文子串、516. 最长回文子序列、动态规划总结
34 1
|
1月前
|
算法
算法系列--动态规划--特殊的状态表示--分析重复子问题(下)
算法系列--动态规划--特殊的状态表示--分析重复子问题(下)
15 0
|
1月前
|
算法
算法系列--动态规划--特殊的状态表示--分析重复子问题(上)
算法系列--动态规划--特殊的状态表示--分析重复子问题
18 0