• 痛定思痛学DP,动态规划的一般性应用流程的总结


    Dynamic Programming

    动态规划

    DP问题

    【动态规划专题班】ACM总冠军、清华+斯坦福大神带你入门动态规划算法

    目的:空间换时间,提升效率

    方式:找出有规律性的递推公式以及限定条件

    动态规划关键词

    • 每一步最优
    • 将问题划分为重复的子问题【到n-1步为整体 + 接下来的后一步】
      • 所以每次问题的形式是一致的,只是具体数据不同
      • f n = f n − 1 + 第 n 步 f_n = f_{n-1} + 第n步 fn=fn1+n
      • f i , j . . . f_{i,j} ... fi,j...
    • 把问题以归纳方式从最基础范围开始递进
      • 因为第n步的结果就是前n-1步得到的最优结果加上第n步的结果,取最优得到
      • 因此避免重复计算,需要记录每步的结果

    何时使用动态规划

    问结果但不是具体内容的,求的是具体一个数,一般用DP比如

    • 计数问题
      • 多少种路径
      • 多少种方法
    • 求最大最小值
      • 子序列长度(最长、最短)
      • 数字和
    • 求存在性
      • 先手是否取胜
      • 能不能选k个数使和最大

    问所有种类的结果的内容,一般递归,深度搜索这些。

    而,递归做了很多重复计算,因此可以将计算结果保存下来,避免重复计算。

    动态问题的一般性处理步骤

    一、确定状态

    也就是 f n , f i , j f_n,f_{i,j} fn,fi,j之类的

    问题分割为2部分:

    • 最后一步

    • 子问题

      • 把问题的规模缩小,但是问题都是一致的,同样的问题,求得范围更小

    二、转移方程

    就是递进的规律方程,把子问题和最后一步的联系规律找到了

    比如:

    f X = m i n { f X − 2 + 1 , f X − 5 + 1 , f X − 7 + 1 } f_X = min\{f_{X-2}+1, f_{X-5}+1, f_{X-7}+1\} fX=min{fX2+1,fX5+1,fX7+1}

    这里表达了 f x f_x fx(最后一步)和 f X − f_{X-} fX(子问题)的关系

    三、初始条件和边界情况

    初始条件

    最开始(小范围)的数值,用于初始化,人工设定

    (这些初始值用转移方程是算不出来的,然后后面递进计算又要用到的值)

    比如:

    • 一维情况下, f 0 , f 1 f_0,f_1 f0,f1
    • 二维情况下, f 0 , 0 , f 0 , 1 , f 1 , 0 f_{0,0},f_{0,1},f_{1,0} f0,0,f0,1,f1,0

    这个维数和遍历对应,也和需要的变量对应

    边界条件

    对于每次迭代计算,都要在合理的边界下计算

    比如不存在的情况下,返回null

    四、计算顺序

    从前往后、从小往大、从大到小等。。。

    顺序原则:看计算要依赖的方向,也就是转移方程中,谁靠谁得到后续的结果

    demo1 青蛙跳石头

    问题:在学习视频,1:10:52的地方

    • 有n块石头分别在x轴的0,1,… n-1位置·一只青蛙在石头0,想跳到石头n-1
    • 如果青蛙在第i块石头上,它最多可以向右跳距离 a i a_i ai;
    • 问青蛙能否跳到石头n-1
    • 例子∶
      • 输入:a=[2, 3, 1, 1, 4]
      • 输出:True
      • 输入:a=[3, 2, 1, 0, 4]
      • 输出:False

    思路(按照方法先自己想的)

    • 一、确定状态,分离子问题和最后一步

      蛙能否跳到n-1,能否跳到n-2,…,能否跳到1。

    • 二、确定转移方程

      f n = ( f 0 + r e s t 0 ) ∣ ∣ ( f 1 + r e s t 1 ) ∣ ∣ . . . ∣ ∣ ( f n − 1 + r e s t n − 1 ) ∣ ∣ ( f n + r e s t n ) f_n = (f_0 + rest_0) || (f_1 + rest_1) || ... || (f_{n-1} + rest_{n-1}) || (f_n + rest_n) fn=(f0+rest0)∣∣(f1+rest1)∣∣...∣∣(fn1+restn1)∣∣(fn+restn)

      r e s t i rest_i resti表示在石头 n i n_i ni处剩下需要跳的数,跳过了,就 t r u e true true

      有一个 t r u e true true就返回 t r u e true true

    • 三、确定边界和初始值

      就n块石头

      f 0 = t r u e f_0=true f0=true

    • 四、整体总结

      需要一个一维变量boolean [n] re,记录是否可以跳到对应下标的石头上

      所以,数组re应该初始化为false,能跳再改为true

    • 五、代码(没验证,凭感觉走的)

    public boolean jump(int[] stone){
        // stone数组就是题目示例的数组a
        //定义数组re存结果
        n = stone.length;
        int[] re = new int[n];
        re[0] = true; //初始化
        
        for(int i = 0; i < n; i++){
            //得到在每块石头上的结果
            for(int j = 0; j < stone[i]; j++){
                if(re[j]){//代表可以跳到这块石头上
                    re[i+j] = true; //把能跳的地方
                }
            }
        }
        return re[n-1];
    }
    
  • 相关阅读:
    基于51单片机蓝牙智能控制风扇-proteus仿真-源程序
    SQL-去除最大值与最小值求均值的问题
    操作系统—死锁
    一种辅助自律的方式:暑假学习生活打卡的数据分析及思考
    Unity Text文字超过长度显示为省略号
    【数学模拟卷总结】2023李林六套卷数学二第三套
    [附源码]Python计算机毕业设计Django基于web的羽毛球管理系统
    UNCTF2022 writeup
    企业电子招投标系统源码之电子招投标系统建设的重点和未来趋势
    3环境变量
  • 原文地址:https://blog.csdn.net/qq_37774098/article/details/127044395