NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)

  1. 记忆化搜索
    在搜索的过程中,如果搜索树中有很多重复的结点,此时可以通过⼀个"备忘录",记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时,直接在"备忘录"⾥⾯找结果。其中,搜索树中的⼀个⼀个结点,也称为⼀个⼀个状态。
    ⽐如经典的斐波那契数列问题
int f[N]; // 备忘录  int fib(int n)  
{  // 搜索之前先往备忘录⾥⾯瞅瞅  if(f[n] != -1) return f[n];  if(n == 0 || n == 1) return f[n] = n;  // 返回之前,把结果记录在备忘录中  f[n] = fib(n - 1) + fib(n - 2);  return f[n];  
}
  1. 递归改递推
    在⽤记忆化搜索解决斐波那契问题时,如果关注"备忘录"的填写过程,会发现它是从左往右依次填写的。当i位置前⾯的格⼦填写完毕之后,就可以根据格⼦⾥⾯的值计算出i位置的值。所以,整个递归过程,我们也可以改写成循环的形式,也就是递推
int f[N]; // f[i] 表⽰:第 i 个斐波那契数  
int fib(int n)  
{  // 初始化前两个格⼦  f[0] = 0; f[1] = 1;  // 按照递推公式计算后⾯的值  for(int i = 2; i <= n; i++)  {  f[i] = f[i - 1] + f[i - 2];  }  // 返回结果  return f[n];  
}
  1. 动态规划
    动态规划(Dynamic Programming,简称DP)是⼀种⽤于解决多阶段决策问题的算法思想。它通过将复杂问题分解为更⼩的⼦问题,并存储⼦问题的解(通常称为“状态”),从⽽避免重复计算,提⾼效率。因此,动态规划⾥,蕴含着分治与剪枝思想。
    上述通过记忆化搜索以及递推解决斐波那契数列的⽅式,其实都是动态规划。
    注意:
  • 动态规划中的相关概念其实远不⽌如此,还会有:重叠⼦问题、最优⼦结构、⽆后效性、有向⽆环图等等。
  • 这些概念没有⼀段时间的沉淀是不可能完全理解的。可以等学过⼀段时间之后,再去接触这些概念。不过,这些概念即使不懂,也不影响做题~
    在递推形式的动态规划中,常⽤下⾯的专有名词来表述:
  1. 状态表⽰:指 f 数组中,每⼀个格⼦代表的含义。其中,这个数组也会称为 dp 数组,或者dp 表。
  2. 状态转移⽅程:指 f 数组中,每⼀个格⼦是如何⽤其余的格⼦推导出来的
  3. 初始化:在填表之前,根据题⽬中的默认条件或者问题的默认初始状态,将 f 数组中若⼲格⼦先填上值。
    其实递推形式的动态规划中的各种表述,是可以对应到递归形式的:
  • 状态表⽰<—>递归函数的意义;
  • 状态转移⽅程<—>递归函数的主函数体;
  • 初始化<—>递归函数的递归出⼝。
  1. 如何利⽤动态规划解决问题
    第⼀种⽅式当然就是记忆化搜索了:
  • 先⽤递归的思想去解决问题;
  • 如果有重复⼦问题,就改成记忆化搜索的形式。
    第⼆种⽅式,直接使⽤递推形式的动态规划解决:
  1. 定义状态表⽰:
    ⼀般情况下根据经验+递归函数的意义,赋予 dp 数组相应的含义。(其实还可以去蒙⼀个,如果蒙的状态表⽰能解决问题,说明蒙对了。如果蒙错了,再换⼀个试~)
  2. 推导状态转移⽅程:
    根据状态表⽰以及题意,在 dp 表中分析,当前格⼦如何通过其余格⼦推导出来。
  3. 初始化:
    根据题意,先将显⽽易⻅的以及边界情况下的位置填上值。
  4. 确定填表顺序:
    根据状态转移⽅程,确定按照什么顺序来填表。
  5. 确定最终结果:
    根据题意,在表中找出最终结果
P10250 [GESP样题 六级] 下楼梯 - 洛谷

因为上楼和下楼是⼀个可逆的过程,因此我们可以把下楼问题转化成上到第n个台阶,⼀共有多少种⽅案。
解法:动态规划

  1. 状态表⽰:
    dp[i] 表⽰:⾛到第i 个台阶的总⽅案数。
    那最终结果就是在dp[n]处取到。
  2. 状态转移⽅程:
    根据最后⼀步划分问题,⾛到第i 个台阶的⽅式有三种:
    a. 从i - 1 台阶向上⾛1 个台阶,此时⾛到i 台阶的⽅案就是dp[i - 1]
    b. 从i - 2 台阶向上⾛2 个台阶,此时⾛到i 台阶的⽅案就是dp[i - 2]
    c. 从i - 3 台阶向上⾛3 个台阶,此时⾛到i 台阶的⽅案就是dp[i - 3]
    综上所述,dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
  3. 初始化:
    填i位置的值时,⾄少需要前三个位置的值,因此需要初始化dp[0] = 1, dp[1] = 1, dp[2] = 2,然后从i = 3开始填。
    或者初始化dp[1] = 1, dp[2] = 2, dp[3] = 4,然后从i = 4 开始填。
  4. 填表顺序:
    明显是从左往右
#include <bits/stdc++.h>
using namespace std;typedef long long LL;const int N = 65;int n;
LL f[N]; //f[i]表示有i个台阶的时候,一共有多少种方案int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;//初始化f[0] = 1; f[1] = 1; f[2] = 2;for (int i = 3; i <= n; i++){f[i] = f[i - 1] + f[i - 2] + f[i - 3];       }cout << f[n] << endl;return 0;
}

动态规划的空间优化:
我们发现,在填写dp[i]的值时,我们仅仅需要前三个格⼦的值,第i-4个及其之前的格⼦的值已经毫⽆⽤处了。因此,可以⽤三个变量记录i位置之前三个格⼦的值,然后在填完i位置的值之
后,滚动向后更新
![[Pasted image 20250409153812.png]]

#include <bits/stdc++.h>
using namespace std;typedef long long LL;const int N = 65;int n;int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;LL a = 1, b = 1, c = 2;for (int i = 3; i <= n; i++){LL t = a + b + c;a = b;b = c;c = t;}if (n == 1) cout << b << endl;else cout << c << endl;return 0;
}
P1216 [IOI 1994] 数字三角形 Number Triangles - 洛谷

![[Pasted image 20250409160024.png]]

学习动态规划最经典的⼊⻔题。
解法:动态规划

  1. 状态表⽰:
    dp[i][j] 表⽰:⾛到[i, j] 位置的最⼤权值。
    那最终结果就是在dp 表的第n ⾏中,所有元素的最⼤值。
  2. 状态转移⽅程:
    根据最后⼀步划分问题,⾛到[i, j] 位置的⽅式有两种:
    a. 从[i - 1, j] 位置向下⾛⼀格,此时⾛到[i, j] 位置的最⼤权值就是dp[i - 1][j]
    b. 从[i - 1, j - 1]位置向右下⾛⼀格,此时⾛到[i, j] 位置的最⼤权值就是dp[i - 1][j - 1]
    综上所述,应该是两种情况的最⼤值再加上[i,j]位置的权值:
    dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j]
  3. 初始化:
    因为dp 表被0 包围着,并不影响我们的最终结果,因此可以直接填表。
    思考,如果权值出现负数的话,需不需要初始化?
    ◦ 此时可以全都初始化为 − ∞ -\infty ,负⽆穷⼤在取max 之后,并不影响最终结果。
  4. 填表顺序:
    从左往右填写每⼀⾏,每⼀⾏从左往右
#include <bits/stdc++.h>
using namespace std;const int N = 1010;int n;
int a[N][N];
int f[N][N]; //f[i][j]表示从1,1走到i,j的时候,所有方案数的最大权值int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++)for (int j = 1; j <= i; j++)cin >> a[i][j];for (int i = 1; i <= n; i++){for (int j = 1; j <= i; j++){f[i][j] = max(f[i-1][j], f[i-1][j-1]) + a[i][j];    }}int ret = 0;for (int j = 1; j <= n; j++){ret = max(ret, f[n][j]);        }cout << ret << endl;return 0;
}

动态规划的空间优化:
我们发现,在填写第i ⾏的值时,我们仅仅需要前⼀⾏的值,并不需要第i - 2 以及之前⾏的值。
因此,我们可以只⽤⼀个⼀维数组来记录上⼀⾏的结果,然后在这个数组上更新当前⾏的值
![[Pasted image 20250409161744.png]]

需要注意,当⽤因为我们当前这个位置的值需要左上⻆位置的值,因此滚动数组优化的时候,要改变第⼆维的遍历顺序

#include <bits/stdc++.h>
using namespace std;const int N = 1010;int n;
int a[N][N];
int f[N]; //f[i][j]表示从1,1走到i,j的时候,所有方案数的最大权值int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++)for (int j = 1; j <= i; j++)cin >> a[i][j];for (int i = 1; i <= n; i++){for (int j = i; j >= 1; j--){f[j] = max(f[j], f[j-1]) + a[i][j];    }}int ret = 0;for (int j = 1; j <= n; j++){ret = max(ret, f[j]);        }cout << ret << endl;return 0;
}

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

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

相关文章

使用 VBA 宏创建一个选择全部word图片快捷指令,进行图片格式编辑

使用 VBA 宏批量选择图片 ✅ 第一步&#xff1a;创建 .dotm 加载项文件 1、使用环境 office word 365&#xff0c;文件格式为.docx 图片格式为.PNG 2、创建 .dotm 加载项文件 打开 Word&#xff0c;新建一个空白文档。 按下 Alt F11 打开 VBA 编辑器。 点击菜单栏&#xff…

深度学习的下一个突破:从图像识别到情境理解

引言 过去十年&#xff0c;深度学习在图像识别领域取得了惊人的突破。从2012年ImageNet大赛上的AlexNet&#xff0c;到后来的ResNet、EfficientNet&#xff0c;再到近年来Transformer架构的崛起&#xff0c;AI已经能在许多任务上超越人类&#xff0c;比如人脸识别、目标检测、医…

使用dyn4j做碰撞检测

文章目录 前言一、环境准备添加依赖基本概念 二、实现步骤1.创建世界2.添加物体3.设置碰撞监听器4.更新世界 三、完整代码示例四、优化补充总结 前言 dyn4j 提供了高效的碰撞检测和物理模拟功能&#xff0c;适用于游戏开发、动画制作以及其他需要物理交互的场景。通过简单的 A…

VS Code settings.json 文件中常用的预定义变量‌及其用途说明

VS Code settings.json 常用预定义变量 以下是 Visual Studio Code 配置文件中常用的预定义变量列表&#xff1a; 1. 工作区相关变量 变量描述示例值${workspaceFolder}当前工作区根目录的绝对路径C:/projects/my-project${workspaceFolderBasename}工作区文件夹名称&#x…

elasticSearch-搜索引擎

搜索引擎的优势 有了数据库分页查询&#xff0c;为什么还需要搜索引擎&#xff1f; 搜索引擎速度上很快数据库分页查询&#xff0c;随着数据库数据量增大&#xff0c;页数靠后&#xff0c;会导致搜索速度变慢&#xff0c;但是搜索引擎不会搜索引擎支持分词查询&#xff0c;地…

安装OpenJDK1.8 17 (macos M芯片)

安装OpenJDK 1.8 下载完后&#xff0c;解压&#xff0c;打开 环境变量的配置文件即可 vim ~/.zshrc #export JAVA_HOME/Users/xxxxx/jdk-21.jdk/Contents/Home #export JAVA_HOME/Users/xxxxx/jdk-17.jdk/Contents/Home #export JAVA_HOME/Users/xxxxx/jdk-11.jdk/Contents…

断言与反射——以golang为例

断言 x.(T) 检查x的动态类型是否是T&#xff0c;其中x必须是接口值。 简单使用 func main() {var x interface{}x 100value1, ok : x.(int)if ok {fmt.Println(value1)}value2, ok : x.(string)if ok {//未打印fmt.Println(value2)} }需要注意如果不接受第二个参数就是OK,这…

Java设计模式:系统性解析与核心模式

一、设计模式三大分类总览 创建型模式&#xff08;5种&#xff09; 核心目标&#xff1a;对象创建的优化与解耦 单例模式&#xff08;Singleton&#xff09; 工厂模式&#xff08;Factory&#xff09; 抽象工厂模式&#xff08;Abstract Factory&#xff09; 建造者模式&#…

Elasticsearch 向量数据库,原生支持 Google Cloud Vertex AI 平台

作者&#xff1a;来自 Elastic Valerio Arvizzigno Elasticsearch 将作为第一个第三方原生语义对齐引擎&#xff0c;支持 Google Cloud 的 Vertex AI 平台和 Google 的 Gemini 模型。这使得联合用户能够基于企业数据构建完全可定制的生成式 AI 体验&#xff0c;并借助 Elastics…

408 计算机网络 知识点记忆(7)

前言 本文基于王道考研课程与湖科大计算机网络课程教学内容&#xff0c;系统梳理核心知识记忆点和框架&#xff0c;既为个人复习沉淀思考&#xff0c;亦希望能与同行者互助共进。&#xff08;PS&#xff1a;后续将持续迭代优化细节&#xff09; 往期内容 408 计算机网络 知识…

10-MySQL-性能优化思路

1、优化思路 当我们发现了一个慢SQL的问题的时候,需要做性能优化,一般我们是为了提高SQL查询更快,一个查询的流程由下图的各环节组成,每个环节都会消耗时间,要减少消耗时候需要从各个环节都分析一遍。 2 连接配置优化 第一个环节是客户端连接到服务端,这块可能会出现服务…

Docker:安装与部署 Nacos 的技术指南

1、简述 Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一个动态服务发现、配置管理和服务治理的综合解决方案,适用于微服务架构。 Nacos 主要功能: 服务发现与注册:支持 Dubbo、Spring Cloud 等主流微服务框架的服务发现与注册。动态配置管理:支持…

【非机动车检测】用YOLOv8实现非机动车及驾驶人佩戴安全帽检测

非机动车及驾驶人佩戴安全帽检测任务的意义主要包括以下几点&#xff1a; 保障行车安全&#xff1a;非机动车包括自行车、电动车等&#xff0c;佩戴安全帽能够有效保护骑车人头部&#xff0c;减少因交通事故造成的头部伤害风险&#xff0c;提高行车安全系数。 符合交通法规&am…

壹起航:15年深耕互联网营销,助力中国工厂出海获客

在全球化浪潮下&#xff0c;越来越多的中国工厂渴望拓展海外市场&#xff0c;但面临品牌建立、稳定询盘获取及营销成本降低等多重挑战。壹起航凭借15年的丰富经验&#xff0c;整合外贸建站、SEO优化及海外短视频营销&#xff0c;为中国工厂提供一站式出海解决方案。 一、外贸独…

Emacs 折腾日记(二十)——修改emacs的一些默认行为

上一篇我们完成了emacs输入法的配置以及将emacs配置成了使用vim的操作方式。但是emacs目前有些默认行为我不太喜欢&#xff0c;这节我们一起来修改它 备份设置 我们打开emacs的配置文件所在路径&#xff0c;发现有大量的~结尾的文件&#xff0c;这是emacs的备份文件。这里&am…

聊透多线程编程-线程基础-4.C# Thread 子线程执行完成后通知主线程执行特定动作

在多线程编程中&#xff0c;线程之间的同步和通信是一个常见的需求。例如&#xff0c;我们可能需要一个子线程完成某些任务后通知主线程&#xff0c;并由主线程执行特定的动作。本文将基于一个示例程序&#xff0c;详细讲解如何使用 AutoResetEvent 来实现这种场景。 示例代码…

【网络安全 | 项目开发】Web 安全响应头扫描器(提升网站安全性)

原创项目,未经许可,不得转载。 文章目录 项目简介工作流程示例输出技术栈项目代码使用说明项目简介 安全响应头是防止常见 Web 攻击(如点击劫持、跨站脚本攻击等)的有效防线,因此合理的配置这些头部信息对任何网站的安全至关重要。 Web 安全响应头扫描器(Security Head…

使用libcurl编写爬虫程序指南

用户想知道用Curl库编写的爬虫程序是什么样的。首先&#xff0c;我需要明确Curl本身是一个命令行工具和库&#xff0c;用于传输数据&#xff0c;支持多种协议。而用户提到的“Curl库”可能指的是libcurl&#xff0c;这是一个客户端URL传输库&#xff0c;可以用在C、C等编程语言…

使用pip3安装PyTorch与PyG,实现NVIDIA CUDA GPU加速

使用python3的pip3命令安装python依赖库。 # python3 -V Python 3.12.3 # # pip3 -V pip 25.0.1 from /root/.pyenv/versions/3.12.3/lib/python3.12/site-packages/pip (python 3.12)Usage: pip3 install [options] <package> ...pip3 install [options] -r <re…

五种常用的web加密算法

文章目录 五种常用Web加密算法实战及原理详解1. AES (高级加密标准)原理详解应用场景实战代码&#xff08;Node.js&#xff09; 2. RSA (非对称加密)原理详解应用场景实战代码&#xff08;Node.js&#xff09; 3. SHA-256 (安全哈希算法)原理详解应用场景实战代码&#xff08;浏…