动态规划算法

article/2025/6/18 5:38:59

简称 DP,是一种求解多阶段决策过程最优化问题的方法。在动态规划中,通过把原问题分解为相对简单的子问题,先求解子问题,再由子问题的解而得到原问题的解。

一、概念

动态规划最早由理查德 · 贝尔曼于 1957 年在其著作「动态规划(Dynamic Programming)」一书中提出。这里的 Programming 并不是编程的意思,而是指一种「表格处理方法」,即将每一步计算的结果存储在表格中,供随后的计算查询使用。

1. 核心思想

把「原问题」分解为「若干个重叠的子问题」,每个子问题的求解过程都构成一个 「阶段」。在完成一个阶段的计算之后,动态规划方法才会执行下一个阶段的计算。

在求解子问题的过程中,按照「自顶向下的记忆化搜索方法」或者「自底向上的递推方法」求解出「子问题的解」,把结果存储在表格中,当需要再次求解此子问题时,直接从表格中查询该子问题的解,从而避免了大量的重复计算。

这看起来很像是分治算法,但动态规划与分治算法的不同点在于:

  • 适用于动态规划求解的问题,在分解之后得到的子问题往往是相互联系的,会出现若干个重叠子问题。
  • 使用动态规划方法会将这些重叠子问题的解保存到表格里,供随后的计算查询使用,从而避免大量的重复计算

2. 动态规划的简单例子

下面我们先来通过一个简单的例子来介绍一下什么是动态规划算法,然后再来讲解动态规划中的各种术语

通过公式 f(n)=f(n−2)+f(n−1),我们可以将原问题 f(n) 递归地划分为 f(n−2) 和 f(n−1) 这两个子问题。其对应的递归过程如下图所示

从图中可以看出:如果使用传统递归算法计算 f(5),需要先计算 f(3) 和 f(4,而在计算 f(4) 时还需要计算 f(3),这样 f(3)就进行了多次计算。同理 f(0)、f(1)、f(2)都进行了多次计算,从而导致了重复计算问题。

为了避免重复计算,我们可以使用动态规划中的「表格处理方法」来处理。

这里我们使用「自底向上的递推方法」求解出子问题 f(n−2)和 f(n−1)的解,然后把结果存储在表格中,供随后的计算查询使用。具体过程如下:

  1. 定义一个数组 dp,用于记录斐波那契数列中的值。
  2. 初始化 dp[0]=0,dp[1]=1。
  3. 根据斐波那契数列的递推公式 f(n)=f(n−1)+f(n−2),从 dp(2)开始递推计算斐波那契数列的每个数,直到计算出 dp(n)。
  4. 最后返回 dp(n) 即可得到第 n 项斐波那契数。
class Solution {// 计算斐波那契数列的第 n 个元素fib(n) {// 处理特殊情况:n为0时,斐波那契数列的第0个元素为0if (n === 0) {return 0;}// 处理特殊情况:n为1时,斐波那契数列的第1个元素为1if (n === 1) {return 1;}// 初始化动态规划数组,长度为n+1const dp = new Array(n + 1).fill(0);// 初始值:第0个元素为0,第1个元素为1dp[0] = 0;dp[1] = 1;// 从第2个元素开始,通过动态规划计算斐波那契数列的每个元素for (let i = 2; i <= n; i++) {dp[i] = dp[i - 2] + dp[i - 1];}// 返回计算得到的第n个斐波那契数列元素return dp[n];}
}// 示例用法
const solution = new Solution();
const result = solution.fib(7); // 13
console.log(result);

二、动态规划的特征

究竟什么样的问题才可以使用动态规划算法解决呢?

首先,能够使用动态规划方法解决的问题必须满足以下三个特征:

  • 最优子结构性质
  • 重叠子问题性质
  • 无后效性

1. 最优子结构性质

指的是一个问题的最优解包含其子问题的最优解

举个例子,如下图所示,原问题 S={a1,a2,a3,a4} ,在 a1步我们选出一个当前最优解之后,问题就转换为求解子问题 S子问题={a2,a3,a4}。如果原问题 S的最优解可以由「第 a1步得到的局部最优解」和「 S子问题S_子问题的最优解」构成,则说明该问题满足最优子结构性质。

也就是说,如果原问题的最优解包含子问题的最优解,则说明该问题满足最优子结构性质

2. 重叠子问题性质

指的是在求解子问题的过程中,有大量的子问题是重复的,一个子问题在下一阶段的决策中可能会被多次用到。如果有大量重复的子问题,那么只需要对其求解一次,然后用表格将结果存储下来,以后使用时可以直接查询,不需要再次求解

3. 无后效性

指的是子问题的解(状态值)只与之前阶段有关,而与后面阶段无关。当前阶段的若干状态值一旦确定,就不再改变,不会再受到后续阶段决策的影响。

也就是说,一旦某一个子问题的求解结果确定以后,就不会再被修改

举个例子,下图是一个有向无环带权图,我们在求解从 A 点到 F 点的最短路径问题时,假设当前已知从 A点到 D点的最短路径(2+7=9)。那么无论之后的路径如何选择,都不会影响之前从 AAA 点到 DDD 点的最短路径长度。这就是「无后效性」。

而如果一个问题具有「后效性」,则可能需要先将其转化或者逆向求解来消除后效性,然后才可以使用动态规划算法。

三、动态规划的基本思路

如下图所示,我们在使用动态规划方法解决某些最优化问题时,可以将解决问题的过程按照一定顺序(时间顺序、空间顺序或其他顺序)分解为若干个相互联系的「阶段」。然后按照顺序对每一个阶段做出「决策」,这个决策既决定了本阶段的效益,也决定了下一阶段的初始状态。依次做完每个阶段的决策之后,就得到了一个整个问题的决策序列。

这样就将一个原问题分解为了一系列的子问题,再通过逐步求解从而获得最终结果。

这种前后关联、具有链状结构的多阶段进行决策的问题也叫做「多阶段决策问题」。

通常我们使用动态规划方法来解决问题的基本思路如下:

  1. 划分阶段:将原问题按顺序(时间顺序、空间顺序或其他顺序)分解为若干个相互联系的「阶段」。划分后的阶段⼀定是有序或可排序的,否则问题⽆法求解。
    • 这里的「阶段」指的是⼦问题的求解过程。每个⼦问题的求解过程都构成⼀个「阶段」,在完成前⼀阶段的求解后才会进⾏后⼀阶段的求解。
  1. 定义状态:将和子问题相关的某些变量(位置、数量、体积、空间等等)作为一个「状态」表示出来。状态的选择要满⾜⽆后效性。
    • 一个「状态」对应一个或多个子问题,所谓某个「状态」下的值,指的就是这个「状态」所对应的子问题的解。
  1. 状态转移:根据「上一阶段的状态」和「该状态下所能做出的决策」,推导出「下一阶段的状态」。或者说根据相邻两个阶段各个状态之间的关系,确定决策,然后推导出状态间的相互转移方式(即「状态转移方程」)。
  2. 初始条件和边界条件:根据问题描述、状态定义和状态转移方程,确定初始条件和边界条件。
  3. 最终结果:确定问题的求解目标,然后按照一定顺序求解每一个阶段的问题。最后根据状态转移方程的递推结果,确定最终结果。

http://www.hkcw.cn/article/xBSeYVhlSO.shtml

相关文章

Qt -使用OpenCV得到SDF

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【暂无】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 目录 cv::MatdistanceTransform获得SDF 本文的目标&#xff0c; 是简单学习并使用OpenCV的相关函数&#xff0c; 并获得QImage的SDF(Signed Distance Field 有向距离场) 至…

【小米拥抱AI】小米开源 MiMo-7B-RL-0530

更新日志 [2025.05.30] 在强化学习训练过程中&#xff0c;通过持续扩大训练窗口尺寸&#xff08;从32K提升至48K&#xff09;&#xff0c;MiMo-7B-RL-0530模型在AIME24基准测试上的表现持续提升&#xff0c;最终超越DeepSeek R1模型的性能水平。 BenchmarkMiMo-7B-RLMiMo-7B-…

俄布良斯克州桥梁坍塌致列车脱轨事故造成3死28伤

△图片来源:莫斯科交通检察院总台记者当地时间6月1日获悉,据俄罗斯紧急情况部初步统计,布良斯克州桥梁坍塌致火车脱轨事故共造成31人伤亡,其中3人不幸遇难,28人已送往医疗机构救治。此前据俄罗斯BAZA网站报道,事件造成4人死亡,至少44人受伤。俄紧急情况部称,救援人员正…

JDK17 与JDK8 共同存在一个电脑上

官网下载JDK17 官网链接 &#xff1a;https://www.oracle.com/java/technologies/downloads/#java17-windows 下载这个 安装 环境变量设置 因为之前设置过JDK 8这里为了使 两者共存&#xff0c;采用设置变量方式来实现具体操作如下 1、进入高级系统环境设置 1.1先建一个关…

打开NRODIC SDK编译不过怎么处理,keil与segger studio

打开NRODIC SDK编译不过怎么处理,以下是keil处理. 1,如图,不要安装安装也不会过 2. 不要安装点击否 3.点击确定后进来这个样子 4.这里选择这个勾,OK后就不会再有后面的pack_license 5.去掉勾后这里要选择自己SDK对应的pack版本,我的是8.27.0 6.OK后弹出个界面也要反复选择…

每日八股文5.31

每日八股-5.31 Go1.切片是值传递还是引用传递&#xff1f;2.切片的深拷贝与浅拷贝3.切片的底层实现4.切片的扩容机制5.Map是线程安全的吗&#xff1f;6.哪些类型可以作为map的key&#xff1f;7.Map删除一个key内存是否会释放&#xff1f;8.Map为什么是无序的&#xff1f;9.如何…

智能重塑连接:AI原生互联网的范式革命与未来十年

引言:互联网的下一幕——智能涌现与体验重塑 2024年初,OpenAI发布的文生视频模型Sora,以其惊人的逼真度和对物理世界的理解能力,再次将人工智能的魔力推向了全球聚光灯下。这不仅仅是一个技术演示,更像是一个强烈的信号:我们正加速驶向一个由AI深度重塑的未来。回望互联…

【深度学习相关安装及配环境】Anaconda搭建虚拟环境并安装CUDA、cuDVV和对应版本的Pytorch,并在jupyter notebook上部署

目录 1. 查看自己电脑的cuda版本2.安装cuda关于环境变量的配置测试一下&#xff0c;安装完成 3.安装cuDVV环境变量的配置测试一下&#xff0c;安装完成 4.创建虚拟环境先安装镜像源下载3.11版本py 5.在虚拟环境下&#xff0c;下载pytorch6.验证是否安装成功7.在jupyter noteboo…

2. 手写数字预测 gui版

2. 手写数字预测 gui版 背景1.界面绘制2.处理图片3. 加载模型4. 预测5.结果6.一点小问题 背景 做了手写数字预测的模型&#xff0c;但是老是跑模型太无聊了&#xff0c;就配合pyqt做了一个可视化界面出来玩一下 源代码可以去这里https://github.com/Leezed525/pytorch_toy拿 …

用JS实现植物大战僵尸(前端作业)

1. 先搭架子 整体效果&#xff1a; 点击开始后进入主场景 左侧是植物卡片 右上角是游戏的开始和暂停键 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…

巴黎球迷打出TIFO悼念恩里克女儿 感人至深的纪念

北京时间6月1日,巴黎圣日耳曼在欧冠决赛中以5-0战胜国际米兰,夺得本赛季欧冠冠军。赛后,安联球场展示了一个感人至深的TIFO,主角是巴黎圣日耳曼主教练恩里克和他的已故女儿Xana。十年前,恩里克带领巴塞罗那夺得欧冠冠军时,曾与女儿Xana一起将巴萨的旗帜插进球场。然而,X…

六一儿童节 实践我先行活动举行

5月30日,在“六一”国际儿童节来临之际,“实践我先行——2025年在宋庆龄奶奶生活过的地方过六一”活动在北京宋庆龄故居举行,逾百名中外少年儿童和教师代表参加。活动现场,北京市西城区金融街惠泽幼儿园的小朋友们表演了群鼓节目《华夏少年》。中国宋庆龄基金会党组书记、副…

阿什拉夫弑旧主 破门后拒绝庆祝 情深义重

在欧冠决赛中,巴黎圣日耳曼迎战国际米兰。上半场,阿什拉夫攻破了老东家的大门,帮助巴黎取得领先。这位现年26岁的摩洛哥后卫曾在2020年至2021年效力于国际米兰,并为蓝黑军团出场45次。比赛进行到第12分钟时,阿什拉夫推射空门得手,将比分改写为1-0。进球后,他举起双手,拒…

端午安康(Python)

端午节总算是回家了&#xff0c;感觉时间过得真快&#xff0c;马上就毕业了&#xff0c;用Python弄了一个端午节元素的界面&#xff0c;虽然有点不像&#xff0c;祝大家端午安康。端午节粽子&#xff08;python&#xff09;_python画粽子-CSDN博客https://blog.csdn.net/weixin…

10.安卓逆向2-frida hook技术-frida基本使用-frida指令(用于hook)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…

# CppCon 2014 学习: Quick game development with C++11/C++14

这是一个关于游戏开发与现代 C&#xff08;尤其是 C11/C14&#xff09;结合的技术分享或讲座的概要&#xff0c;结构清晰、内容分为几个部分&#xff1a; About This Talk — 内容结构 1. 导言部分&#xff08;Introductory part&#xff09; 介绍为什么选择游戏开发作为主题…

vscode不满足先决条件问题的解决——vscode的老版本安装与禁止更新(附安装包)

目录 起因 vscode更新设置的关闭 安装包 结语 起因 由于主包用的系统是centos的&#xff0c;且版本有点老了&#xff0c;再加上vscode现在不支持老版本的&#xff0c;这对主包来说更是雪上加霜啊 但是主包看了网上很多教程&#xff0c;眼花缭乱&#xff0c;好多配置要改&…

如何手搓扫雷(待扩展)

文章目录 一、扫雷游戏分析与设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析1.2.2 文件结构设计 二、扫雷游戏的代码实现三、扫雷游戏的扩展总结 一、扫雷游戏分析与设计 扫雷游戏网页版 1.1 扫雷游戏的功能说明 使用控制台&#xff08;黑框框的程序&a…

Python打卡训练营学习记录Day41

DAY 41 简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 →…

我们来学mysql -- mysql8.4主从

mysql8.4主从 8.4安装主从原理主my.cnf启动创建复制用户 从my.cnf启动锁库&迁移数据连接主&开启复制检查复制 8.4安装 参考保姆级安装教程传送门 主从原理 从库准备 使用 CHANGE MASTER TO 配置主库信息并写入 master.info 文件。执行 START SLAVE 启动从库&#xff…