首页 > 其他分享 >动态规划Dp

动态规划Dp

时间:2024-04-10 20:33:49浏览次数:23  
标签:10 台阶 递归 问题 计算 动态 规划 Dp

什么是动态规划?

动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

以上定义来自维基百科,看定义感觉还是有点抽象。简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。

动态规划核心思想

动态规划最核心的思想,就在于拆分子问题,记住过往,减少重复计算

我们来看下,网上比较流行的一个例子:

  • A : "1+1+1+1+1+1+1+1 =?"
  • A : "上面等式的值是多少"
  • B : 计算 "8"
  • A : 在上面等式的左边写上 "1+" 呢?
  • A : "此时等式的值为多少"
  • B : 很快得出答案 "9"
  • A : "你怎么这么快就知道答案了"
  • A : "只要在8的基础上加1就行了"
  • A : "所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'"

一个例子带你走进动态规划 -- 青蛙跳阶问题

暴力递归

leetcode原题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。

有些小伙伴第一次见这个题的时候,可能会有点蒙圈,不知道怎么解决。其实可以试想:

  • 要想跳到第10级台阶,要么是先跳到第9级,然后再跳1级台阶上去;要么是先跳到第8级,然后一次迈2级台阶上去。
  • 同理,要想跳到第9级台阶,要么是先跳到第8级,然后再跳1级台阶上去;要么是先跳到第7级,然后一次迈2级台阶上去。
  • 要想跳到第8级台阶,要么是先跳到第7级,然后再跳1级台阶上去;要么是先跳到第6级,然后一次迈2级台阶上去。

假设跳到第n级台阶的跳数我们定义为f(n),很显然就可以得出以下公式:

f(10) = f(9)+f(8)
f (9)  = f(8) + f(7)
f (8)  = f(7) + f(6)
...
f(3) = f(2) + f(1)

即通用公式为: f(n) = f(n-1) + f(n-2)

那f(2) 或者 f(1) 等于多少呢?

  • 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2;
  • 当只有1级台阶时,只有一种跳法,即f(1)= 1;

因此可以用递归去解决这个问题:

class Solution {
    public int numWays(int n) {
    if(n == 1){
        return 1;
    }
     if(n == 2){
        return 2;
    }
    return numWays(n-1) + numWays(n-2);
    }
}

提交一下,发现有问题,超出时间限制了

因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,爆炸增长的,如果n比较大的话,超时很正常的了。

回过头来,你仔细观察这颗递归树,你会发现存在大量重复计算,比如f(8)被计算了两次,f(7)被重复计算了3次...所以这个递归算法低效的原因,就是存在大量的重复计算

既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去备忘录查一下,如果有,就直接取就好了,备忘录没有才开始计算,那就可以省去重新重复计算的耗时啦!这就是带备忘录的解法。

带备忘录的递归解法(自顶向下)

一般使用一个数组或者一个哈希map充当这个备忘录

动态规划有几个典型特征,最优子结构、状态转移方程、边界、重叠子问题。在青蛙跳阶问题中:

我们来看下自底向上的解法,从f(1)往f(10)方向

  • 要计算原问题 f(10),就需要先计算出子问题 f(9) 和 f(8)
  • 然后要计算 f(9),又要先算出子问题 f(8) 和 f(7),以此类推。
  • 一直到 f(2) 和 f(1),递归树才终止。

    我们先来看看这个递归的时间复杂度吧:

    递归时间复杂度 = 解决一个子问题时间*子问题个数
    
  • 一个子问题时间 = f(n-1)+f(n-2),也就是一个加法的操作,所以复杂度是 O(1);
  • 问题个数 = 递归树节点的总数,递归树的总节点 = 2^n-1,所以是复杂度O(2^n)。
  • 第一步,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来=
  • 第二步, f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在啦,所以可以省掉,f(7),f(6)都需要计算出来
  • 第三步, f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在了
  • 其实,还可以用动态规划解决这道题。

    自底向上的动态规划

    动态规划跟带备忘录的递归解法基本思想是一致的,都是减少重复计算,时间复杂度也都是差不多。但是呢:

  • 带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为自顶向下的解法。
  • 动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为自底向上的解法。
  • f(n-1)和f(n-2) 称为 f(n) 的最优子结构
  • f(n)= f(n-1)+f(n-2)就称为状态转移方程
  • f(1) = 1, f(2) = 2 就是边界啦
  • 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。

代码实现

我们实现代码的时候,一般注意从底往上遍历哈,然后关注下边界情况,空间复杂度,也就差不多啦。动态规划有个框架的,大家实现的时候,可以考虑适当参考一下:

dp[0][0][...] = 边界值
for(状态1 :所有状态1的值){
    for(状态2 :所有状态2的值){
        for(...){
          //状态转移方程
          dp[状态1][状态2][...] = 求最值
        }
    }
}

 

标签:10,台阶,递归,问题,计算,动态,规划,Dp
From: https://blog.csdn.net/back_room/article/details/137609199

相关文章

  • 【多UAV航迹规划】基于ACO蚁群优化的多UAV航迹规划算法matlab仿真
    目录1.算法仿真效果2.MATLAB源码3.算法概述3.1ACO蚁群优化算法原理......
  • 位数问题-dp
    #include<bits/stdc++.h>#defineintlonglong#defineendl'\n'usingnamespacestd;constintmod=12345;//dp[i][0]是前i位有偶数个3的个数//dp[i][1]是前i位有奇数个3的个数intdp[10005][2];voidsolve(){ intn; cin>>n; dp[0][0]=1; dp[0][1]=0; for......
  • ROS中自定义全局算法规划器(c++)
     ros中编写一个全局路径规划器并集成为ros插件,加载到turtlebot3机器人平台上仿真验证参考资料:ROS中自定义全局规划器(上)_算法部署_哔哩哔哩_bilibili官网教程:navigation/Tutorials/WritingAGlobalPathPlannerAsPlugininROS-ROSWiki1.建立工作空间mkdir-pjps_......
  • 掘金设置动态头像
    粘贴到控制台运行就行了avatar=后面的就是你的头像的地址,可以先去掘金评论区评论一张动图,然后拿到在线链接沾到里面就行了fetch("https://juejin.cn/web/user/update/user_info/",{"headers":{"accept":"*/*","accept-language":"zh-CN,zh;q=0.9,en;q=......
  • uniapp转译微信小程序动态样式语法问题(:style)
    这样书写之后编译成微信小程序时会出现一下情况造成此类原因是因为我们直接给了一个对象而不是字符串(即直接给字符串不会出现此类问题)而微信不能直接识别所以直接在动态赋值时加上中括号......
  • 【TensorRT】TensorRT C# API 项目更新 (1):支持动态Bath输入模型推理(下篇)
    4.接口应用关于该项目的调用方式在上一篇文章中已经进行了详细介绍,具体使用可以参考《最新发布!TensorRTC#API:基于C#与TensorRT部署深度学习模型》,下面结合Yolov8-cls模型详细介绍一下更新的接口使用方法。4.1创建并配置C#项目 首先创建一个简单的C#项目,然后添加项......
  • ADP-2-20+ 信号调节 20MHz-2GHzRF功分器 合路器
    ADP-2-20+是一款由Mini-Circuits公司出产的功分器(powerdivider)。这款功分器的工作温度规模为-40°C至85°C,贮存温度规模为-55°C至100°C。作为分路器,它的电源输入最高可达1W,内部功耗最大为0.125W。假如超越这些限制,可能会导致功分器发生永久性损坏。此外,ADP-2-20+还具有低......
  • 二十九 4009. 收集卡牌 (数学期望|状压DP)
    4009.收集卡牌(数学期望|状压DP)略importjava.util.*;publicclassMain{privatestaticfinalintN=16,M=1<<N;privatestaticintn,m;privatestaticdouble[]p=newdouble[N];privatestaticdouble[][]dp=newdouble[M][N*5......
  • 3.IP地址规划设计技术
    3.1十进制与二进制转换3.2IP地址分类A:0~127.xxx.xxx.xxx可以表示2的7次方个网络位,可以表示2的24次方-2个主机位,(24个全0表示网络地址,24个全1为直接广播地址下同)B:128~191.xxx.xxx.xxx可以表示2的14次方个网络位,可以表示2的16次方-2个主机位,C:192~223.xxx.xxx.xxx可......
  • python写的收Udp消息后,再发到 MQTT 的例子
    收到Udp消息后,再发到MQTT的例子完整代码udp2mqtt.pyimportjsonimportloggingimportrandomimportsocketimporttimeimportpaho.mqtt.clientasmqtt_clientBROKER='*******.ala.cn-hangzhou.emqxsl.cn'PORT=8084TOPIC="python-mqtt/wss"CLIEN......