一文带你学习,动态规划算法

news2024/11/28 18:58:48

一文带你学习,动态规划算法

  • 1.什么是动态规划(DP)
  • 2.青蛙跳台阶问题
    • 暴力递归解法
    • 自顶向下的递归解法
    • 自底向上的动态规划解法
  • 3.动态规划的解题套路
    • 穷举分析
    • 确定边界
    • 确定最优子结构
    • 写出状态转移方程
  • 4.经典线性DP:数字三角形
  • 5.01背包:摘花生

1.什么是动态规划(DP)

动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法

一般这些子问题很相似,可以通过函数关系式(DP方程)递推出来。动态规划就致力于解决每个子问题一次,减少重复计算。其核心思想就是:拆分子问题,记住过往,减少重复计算

一个具体的例子:

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


2.青蛙跳台阶问题

青蛙跳台阶问题

在这里插入图片描述

暴力递归解法

要想到第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) 等于多少呢?显然f(2) = 2,f(1) = 1

于是我们萌生了使用暴力递归解题的方法:

class Solution {
public:
    int numWays(int n) {
        if(n == 1 || n == 0) {
            return 1;
        }
        if(n == 2) {
            return 2;
        }
        return (numWays(n-1) + numWays(n-2)) % 1000000007;
    }
};

一发提交直接TLE:

在这里插入图片描述

分析算法的时间复杂度:

在这里插入图片描述

递归时间复杂度 = 解决一个子问题时间(本例为1)*子问题个数

问题个数 = 递归树节点的总数,递归树的总节点 = 2^n-1,所以是复杂度O(2^n)

本题数据范围n的最大值为100,而2的100次方等于1.2676506e+30,惊人的数字!

自顶向下的递归解法

一般使用一个数组或者一个哈希map充当一个备忘录,保存之前求解过的值,避免重复计算

  • 第一步,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)全部都在备忘录上了,所以都可以剪掉
    在这里插入图片描述

实现算法:

class Solution {
public:
    int arr[100 + 5];  // 这个数组用作备忘录
    int numWays(int n) {
        if(n == 1 || n == 0) {
            return 1;
        }
        if(n == 2) {
            return 2;
        }
        if(arr[n] !=0) {
            return arr[n];
        } else {
            arr[n] = (numWays(n - 1) + numWays(n - 2)) % 1000000007;
            return arr[n];
        }
    }
};

自底向上的动态规划解法

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

  • 带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为自顶向下的解法。
  • 动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为自底向上的解法。

在这里插入图片描述

实现算法:

class Solution {
public:
    int dp[100 + 5]; // DP数组
    int numWays(int n) {
        if(n <= 1) {
            return 1;
        }
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2 ; i <= n ; i++) {
            dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
        }
        return dp[n];
    }
};

算法的世界多么美妙!


3.动态规划的解题套路

如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。如最长递增子序列、最小编辑距离、背包问题、凑零钱问题等等,都是动态规划的经典应用场景

穷举分析

  • 当台阶数是1的时候,有一种跳法,f(1) =1
  • 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2
  • 当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) =3
  • 当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) =5

在这里插入图片描述

确定边界

f(1) =1,f(2) = 2就是青蛙跳阶的边界,因为我们可以明确这两个结果的准确值

确定最优子结构

n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-2) 称为 f(n) 的最优子结构

一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质

写出状态转移方程

在这里插入图片描述


4.经典线性DP:数字三角形

IMUSTACM:数字三角形

本题是一道非常经典且历史悠久的动态规划题,其作为算法题出现,最早可以追溯到 1994 年的 IOI(国际信息学奥林匹克竞赛)的 The Triangle。时光飞逝,经过 20 多年的沉淀,往日的国际竞赛题如今已经变成了动态规划的入门必做题,不断督促着我们学习和巩固算法

在这里插入图片描述

在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

在这里插入图片描述

穷举分析

要求总路径的最大值,就要求出走到最后一排数字每个数字的最大值,再对最后一排结果取最大值

同时,以2为例,走到它有两种情况,一个是来自左上角f(i-1,j-1)7,一个是来自右上角f(i-1,j)4,事实上,我们只要分析出f(i-1,j-1)f(i-1,j)那个较大取之即可

同理,对于2左上角的7,走到它有两种情况,一个是来自左上角f(i-1,j-1)8,一个是来自右上角f(i-1,j)1

f(1,1) 等于多少呢?显然f(1,1) =数字三角形的第一个数字

确定边界

f(1,1) =a(1,1)就是数字三角形的边界,因为我们可以明确这两个结果的准确值

确定最优子结构,写出状态转移方程

max(f[i-1][j-1] + a[i][j] , f[i-1][j] + a[i][j])

题解代码:

#include <bits/stdc++.h>
using namespace std;
const int N=110;
int a[N][N],f[N][N];
int main()
{
    int n;
    scanf("%d",&n);
    // 输入数字三角形
    for(int i = 1 ;i <= n ; i++)
        for(int j = 1 ; j <= i ; j++)
            scanf("%d",&a[i][j]);

    f[1][1] = a[1][1];

    for(int i = 2 ; i <= n ; i++)
        for(int j = 1 ; j <= i ; j++)
            f[i][j] = max(f[i-1][j-1] + a[i][j] , f[i-1][j] + a[i][j]);

    // 求解最后一排数字的最大值得到结果
    int res = -0x3f3f3f3f;
    for(int i = 1 ; i <= n ; i++)
        res = max(res , f[n][i]);

    printf("%d",res);

    return 0;
}

5.01背包:摘花生

背包问题(Knapsack problem)是一种组合优化的NP完全问题。 问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。 问题的名称来源于如何选择最合适的物品放置于给定背包中。

IMUSTACM:摘花生

在这里插入图片描述

题解代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int f[N][N],w[N][N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t,r,c;
    cin >> t;
    while(t--)
    {
        cin >> r >> c;
        for(int i = 1 ; i <= r ; i++)
            for(int j = 1 ; j <= c ; j++)
                cin >> w[i][j];

        for(int i = 1 ; i <= r ; i++)
            for(int j = 1 ; j <= c ; j++)
                f[i][j] = max(f[i-1][j] , f[i][j-1]) + w[i][j];
        cout << f[r][c] << endl;
    }
    return 0;
}

推荐资源:背包九讲

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

金鸡奖提名电影《巴林塔娜》,主题曲和腾格尔合作是未卜先知吗

在刚刚结束的第三十五届金鸡奖上&#xff0c;由十月天传媒推送的电影《巴林塔娜》&#xff0c;获得了最佳提名奖的荣誉。根据资料显示&#xff0c;十月天传媒是来自北京的一家公司&#xff0c;也是国内最具专业的综合性文化产业运营机构。 话说十月天传媒的董事长袁熙伯先生&am…

Qt OpenGL(二十四)——Qt OpenGL 核心模式-实现彩色三角形

Qt OpenGL(二十四)——Qt OpenGL 核心模式-实现彩色三角形 我们之前在Qt OpenGL 核心模式版本中,看到了Qt关于OpenGL的例程,是一个旋转的彩色三角形,本篇文章我们就使用OpenGL核心模式,实现这个彩色三角形。 图1 旋转的三角形 一、彩色三角形 上一篇文章(Qt OpenGL 核心…

儿童护眼灯AA好还是AAA好?双十二精选国AA儿童护眼灯

儿童护眼灯选择国AA级好&#xff01; 这是为什么呢&#xff1f;我给大家分析一下&#xff0c;简单来说&#xff0c;我国对台灯的质量要求是根据《读写作业台灯性能要求》中&#xff0c;当中将分为国A和国AA级两种标准&#xff0c;主要是对照度和会走的均匀度进行划分的&#x…

失物招领|基于Web的校园失物招领系统的设计与实现

作者主页&#xff1a;编程千纸鹤 作者简介&#xff1a;Java、前端、Pythone开发多年&#xff0c;做过高程&#xff0c;项目经理&#xff0c;架构师 主要内容&#xff1a;Java项目开发、毕业设计开发、面试技术整理、最新技术分享 收藏点赞不迷路 关注作者有好处 引言&#xff…

Haproxy负载均衡集群

目录 一、HAPorxy简介 二、HAPorxy优点 三、理解四层和七层负载均衡 四、HAProxy与LVS的区别 五、使用Haproxy搭建web群集 1、部署2台web服务器 2、编译安装Haproxy 3、客户端访问测试 六、总结 1、HTTP请求的两种方式 2、haproxy配置文件重要参数说明 一、HAPorxy简介…

c语言:初识指针

初识指针一.指针是什么问题一&#xff1a;指针&#xff0c;指针变量&#xff0c;内存&#xff0c;地址&#xff0c;编号的关系问题二&#xff1a;为什么指针大小是4或8字节二.如何使用指针三.指针类型问题三&#xff1a;既然指针是4个字节&#xff0c;那它是如何放下long类型的…

数据库:Centos7安装解压版mysql5.7图文教程,亲测成功

目录 1、卸载Centos7默认自带的mariadb数据库&#xff0c;避免冲突 2、下载解压版mysql并安装 3、配置mysql 4、mysql客户端访问 Centos7安装mysql5.7解压版完整教程避免踩坑&#xff0c;可以把数据目录和系统目录分开设置。 1、卸载Centos7默认自带的mariadb数据库&#xff0c…

Qt5开发从入门到精通——第十二篇一节(Qt5 事件处理及实例——多线程及简单实例)

提示&#xff1a;欢迎小伙伴的点评✨✨&#xff0c;相互学习c/c应用开发。&#x1f373;&#x1f373;&#x1f373; 博主&#x1f9d1;&#x1f9d1; 本着开源的精神交流Qt开发的经验、将持续更新续章&#xff0c;为社区贡献博主自身的开源精神&#x1f469;‍&#x1f680; 文…

菜鸟Linux(3):环境变量

"Oh heiya New World!" 一、什么是环境变量&#xff1f; 谈起环境变量,也许我们在敲代码的层面上并不关心。在链接的时候,我们从来没有告诉编译器,去哪里找动态库去链接;我们也从来没有告诉进程 执行该进程的用户是谁?以及在命令行解释器时&#xff0c;启动一个进程…

深度学习基础--神经网络(4)参数更新策略,梯度法

导数 导数&#xff1a;表示某个瞬间的变化量&#xff0c;公式定义&#xff1a; df(x)dxlimh→0f(xh)−f(x)h(4.4)\frac{df(x)}{dx} lim_{h \to 0}\frac{f(x h)-f(x)}{h} \tag{4.4} dxdf(x)​limh→0​hf(xh)−f(x)​(4.4) 求导的代码实现&#xff1a; import numpy as np i…

SSM框架-Spring(三)

目录 1 Spring对事务的支持 1.1 引入事务场景 1.2 spring对事务的支持 Spring实现事务的两种方式 Spring事务管理API 1.3 事务属性 1.3.1 事务传播行为 1.3.2 事务隔离级别 1.3.3 事务超时 1.3.4 只读事务 1.3.5 异常回滚事务 1.4 事务的全注解式开发 1.5 声明式事…

玩转SQL:咱们的目标是成为SQL方面的“扫地僧”

引言 (Structured Query Language)标准结构化查询语言简称SQL&#xff0c;编写SQL语句是每位后端开发日常职责中&#xff0c;接触最多的一项工作&#xff0c;SQL是关系型数据库诞生的产物&#xff0c;无论是什么数据库&#xff0c;MySQL、Oracle、SQL Server、DB2、PgSQL....&…

FPGA串口接收Demo

串口接收Demo 简单介绍 在发送数据时将并行数据转换成串行数据来传输&#xff0c;在接收数据时将接收到的串行数据转换成并行数据 空闲状态时&#xff0c;为高电平起始位为一个单位长度低电平&#xff0c;停止位为一个长度高电平 分析 帧格式 8位数据位1位停止位无校验位 …

配电站房监控系统方案

配电站为低压用户配送电能&#xff0c;设有中压进线(可有少量出线)、配电变压器和低压配电装置。计讯物联工业网关下配电站房监控系统方案&#xff0c;24小时对运行设备进行不间断数据采集上传服务器&#xff0c;云平台对接&#xff0c;远程实时在线监控设备运行状态 &#xff…

web前端-javascript-标识符(说明,命名规则、不以数字关键字保留字开头、驼峰命名,补充)

文章目录标识符1. 说明2. 命名规则3. 补充标识符 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><script type"text/javascript">//千万不要这么用/* var if 123;console.log(if); *//…

Linux、阿里云服务器用tomcat部署项目

文章目录一、安装JDK和Tomcat1.1 安装JDK2.2 安装Tomcat二、把项目打包成war包&#xff08;jar也可以&#xff0c;但是有区别&#xff09;三、把war包放进webapps里面四、修改tomcat配置五、修改防火墙和开放端口等设置六、在浏览器访问项目一、安装JDK和Tomcat 1.1 安装JDK …

如果你想跨行转做数据分析师,劝你慎重

随着数字化时代的浪潮&#xff0c;数据分析师成了炽手可热的香饽饽&#xff0c;疫情当下&#xff0c;各行各业的失业人员逐渐增多&#xff0c;所以人人都想转行当数据分析师。作为业内人员&#xff0c;说实话&#xff0c;真的不建议&#xff0c;数据分析师真的不是想象的那么简…

【Webpack】webpack的基础使用详细总结 上(建议收藏)

1- 前言&#xff08;前端工程化&#xff09; 实际的前端开发&#xff1a; 模块化&#xff08;js 的模块化、css 的模块化、其它资源的模块化组件化&#xff08;复用现有的 UI 结构、样式、行为&#xff09;规范化&#xff08;目录结构的划分、编码规范化、接口规范化、文档规范…

代码随想录算法训练营第六天|LeetCode 242. 有效的字母异位词 、349. 两个数组的交集 、 202. 快乐数、1. 两数之和

LeetCode 242. 有效的字母异位词 题目链接&#xff1a;242. 有效的字母异位词 方法一&#xff1a; 分析&#xff1a; 两个字符串里的每个字母的个数相等&#xff0c;那么我对每个字符串里的字符串都进行下排序&#xff0c;排出来后岂不是两个字符串的每个字母如果一一对应就…

高通平台开发系列讲解(AI篇)高通神经网络处理引擎工作流程详解

文章目录 一、Model to Runtime Workflow(模型运行流程)二、Basic SNPE Workflow(基本工作流程)2.1、Converting a Network Model(模型转换)2.2、Quantizing a Model(模型量化)沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要介绍高通平台神经网络处…