动态规划:解决复杂问题的利器(下)

news2024/11/20 6:25:07

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6
🍨 阿珊和她的猫_CSDN个人主页
🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • 4. 动态规划的应用
    • 背包问题
    • 最长公共子序列问题
    • 斐波那契数列问题
  • 5. 动态规划的优化技巧
    • 备忘录法
    • 动态规划表格
    • 状态压缩
  • 6. 总结
    • 动态规划的优势和局限
    • 动态规划在实际问题中的应用

4. 动态规划的应用

背包问题

背包问题(Knapsack Problem)是动态规划的一个经典应用
它描述了在给定总容量的情况下,如何选择物品使得总价值最大。

具体来说,背包问题可以描述为:给定一个物品集合,每个物品有一个重量和一个价值,以及一个固定的背包容量。我们的目标是选择一些物品放入背包中,使得背包中的总价值最大,同时不超过背包的容量。

以下是使用动态规划来解决背包问题的步骤:

一、定义状态

在背包问题中,我们可以定义状态为 dp[i][j],表示在前 i 个物品中,选择重量不超过 j 的物品的最大价值。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在背包问题中,状态转移方程为:

dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i])

其中,dp[i-1][j] 表示不选择第 i 个物品的最大价值,dp[i-1][j - weight[i]] + value[i] 表示选择第 i 个物品的最大价值。

三、计算最优值

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个物品开始,依次计算每个物品的状态转移方程,更新 dp 数组。最终,dp[n][capacity] 就是在所有物品中选择不超过背包容量的物品的最大价值。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

最长公共子序列问题

最长公共子序列问题(Longest Common Subsequence,LCS)是动态规划的另一个经典应用。它描述了在两个字符串中找到最长公共子序列的长度。

具体来说,最长公共子序列问题可以描述为:给定两个字符串 s1s2,找到它们的最长公共子序列的长度。

以下是使用动态规划来解决最长公共子序列问题的步骤:

一、定义状态

在最长公共子序列问题中,我们可以定义状态为 dp[i][j],表示在字符串 s1 的前 i 个字符和字符串 s2 的前 j 个字符中,最长公共子序列的长度。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在最长公共子序列问题中,状态转移方程为:

dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + 1)

其中,dp[i-1][j] 表示在字符串 s1 的前 i-1 个字符和字符串 s2 的前 j 个字符中,最长公共子序列的长度,dp[i][j-1] 表示在字符串 s1 的前 i 个字符和字符串 s2 的前 j-1 个字符中,最长公共子序列的长度,dp[i-1][j-1] + 1 表示在字符串 s1 的前 i-1 个字符和字符串 s2 的前 j-1 个字符中,它们的最后一个字符相同的情况下,最长公共子序列的长度加 1。

三、计算最优值

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个字符开始,依次计算每个字符的状态转移方程,更新 dp 数组。最终,dp[n][m] 就是两个字符串的最长公共子序列的长度。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

斐波那契数列问题

斐波那契数列问题(Fibonacci Number Problem)是动态规划的另一个经典应用
它描述了在给定两个初始值的情况下,如何计算斐波那契数列的后续数值。

具体来说,斐波那契数列问题可以描述为:给定两个整数 ab,计算斐波那契数列中第 n 个数的值。

以下是使用动态规划来解决斐波那契数列问题的步骤:

一、定义状态

在斐波那契数列问题中,我们可以定义状态为 dp[i],表示斐波那契数列中第 i 个数的值。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在斐波那契数列问题中,状态转移方程为:

dp[i] = dp[i-1] + dp[i-2]

其中,dp[i-1] 表示斐波那契数列中第 i-1 个数的值,dp[i-2] 表示斐波那契数列中第 i-2 个数的值。

三、计算最优值

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个数开始,依次计算每个数的状态转移方程,更新 dp 数组。最终,dp[n] 就是斐波那契数列中第 n 个数的值。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

5. 动态规划的优化技巧

备忘录法

备忘录法(Memoization)是一种常用的动态规划优化技巧,它通过存储已经计算过的子问题的解,避免了重复计算,从而提高了算法的效率

具体来说,备忘录法的基本思想是在计算每个状态的最优值时,先检查该状态是否已经计算过,如果已经计算过,则直接返回存储的结果,否则计算该状态的最优值,并将其存储起来,以便下次计算时使用。

以下是使用备忘录法来解决斐波那契数列问题的步骤:

一、定义状态

在斐波那契数列问题中,我们可以定义状态为 dp[i],表示斐波那契数列中第 i 个数的值。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在斐波那契数列问题中,状态转移方程为:

dp[i] = dp[i-1] + dp[i-2]

其中,dp[i-1] 表示斐波那契数列中第 i-1 个数的值,dp[i-2] 表示斐波那契数列中第 i-2 个数的值。

三、使用备忘录

在使用备忘录法时,我们需要创建一个备忘录数组 memo,用于存储已经计算过的状态的解。在计算状态 dp[i] 的最优值时,先检查 memo[i] 是否已经计算过,如果已经计算过,则直接返回 memo[i],否则计算 dp[i] 的值,并将其存储在 memo[i] 中。

四、计算最优值

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个数开始,依次计算每个数的状态转移方程,更新 dp 数组。在计算状态 dp[i] 的最优值时,先检查 memo[i] 是否已经计算过,如果已经计算过,则直接返回 memo[i],否则计算 dp[i] 的值,并将其存储在 memo[i] 中。最终,dp[n] 就是斐波那契数列中第 n 个数的值。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

动态规划表格

动态规划表格(Dynamic Programming Table)是一种常用的动态规划优化技巧,它通过将状态和状态转移方程表示为表格的形式,来提高算法的效率。

具体来说,动态规划表格是一个二维数组,其中每一行表示一个状态,每一列表示一个决策。在表格中,每个元素表示该状态下执行该决策的最优值。

以下是使用动态规划表格来解决斐波那契数列问题的步骤:

一、定义状态

在斐波那契数列问题中,我们可以定义状态为 dp[i],表示斐波那契数列中第 i 个数的值。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在斐波那契数列问题中,状态转移方程为:

dp[i] = dp[i-1] + dp[i-2]

其中,dp[i-1] 表示斐波那契数列中第 i-1 个数的值,dp[i-2] 表示斐波那契数列中第 i-2 个数的值。

三、创建动态规划表格

在使用动态规划表格时,我们需要创建一个二维数组 dp,其中每一行表示一个状态,每一列表示一个决策。在斐波那契数列问题中,我们只需要一行,因为只有一个决策。

四、填充动态规划表格

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个数开始,依次计算每个数的状态转移方程,更新 dp 数组。在计算状态 dp[i] 的最优值时,直接从 dp 表格中获取 dp[i-1]dp[i-2] 的值,进行加法运算,并将结果存储在 dp[i] 中。最终,dp[n] 就是斐波那契数列中第 n 个数的值。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

状态压缩

状态压缩(State Compression)是一种常用的动态规划优化技巧,它通过减少状态的数量,来提高算法的效率

具体来说,状态压缩是指将多个相关的状态合并为一个状态,从而减少状态的数量。在状态压缩中,我们需要选择合适的状态表示方法,使得状态之间的关系能够被有效地表示和处理。

以下是使用状态压缩来解决斐波那契数列问题的步骤:

一、定义状态

在斐波那契数列问题中,我们可以定义状态为 dp[i],表示斐波那契数列中第 i 个数的值。

二、确定状态转移方程

状态转移方程是指根据当前状态和决策来更新状态。在斐波那契数列问题中,状态转移方程为:

dp[i] = dp[i-1] + dp[i-2]

其中,dp[i-1] 表示斐波那契数列中第 i-1 个数的值,dp[i-2] 表示斐波那契数列中第 i-2 个数的值。

三、使用状态压缩

在使用状态压缩时,我们可以将斐波那契数列的前两个数作为初始状态,然后通过迭代计算后续的状态。具体来说,我们可以使用一个数组 dp 来存储状态,其中 dp[0]dp[1] 分别表示斐波那契数列的前两个数。

四、填充状态压缩数组

在确定了状态和状态转移方程后,我们可以通过迭代计算每个状态的最优值,最终得到整个问题的最优解。

具体来说,我们可以从第一个数开始,依次计算每个数的状态转移方程,更新 dp 数组。在计算状态 dp[i] 的最优值时,直接从 dp 数组中获取 dp[i-1]dp[i-2] 的值,进行加法运算,并将结果存储在 dp[i] 中。最终,dp[n] 就是斐波那契数列中第 n 个数的值。

需要注意的是,在实际问题中,可能需要根据问题的具体情况来选择合适的状态表示方法和状态转移方程,并且可能需要使用一些优化技巧来提高算法的效率。

6. 总结

动态规划的优势和局限

动态规划(Dynamic Programming,DP)是一种常用的算法设计技术,它在解决一些复杂问题时具有明显的优势,但也存在一些局限。

动态规划的优势:

  1. 高效性:动态规划可以有效地解决一些具有最优子结构的问题,通常可以在多项式时间内得到最优解。

  2. 简洁性:动态规划的算法设计通常比较简洁,易于理解和实现。

  3. 可扩展性:动态规划可以很容易地扩展到更复杂的问题,只需要修改状态定义和状态转移方程即可。
    在这里插入图片描述

动态规划的局限:

  1. 状态空间爆炸:对于一些问题,状态空间的大小可能会随着输入规模的增加呈指数级增长,导致动态规划无法直接应用。

  2. 无法处理非最优子结构:动态规划只能解决具有最优子结构的问题,如果问题不具有最优子结构,动态规划可能无法提供有效的解决方案。

  3. 数值稳定性:在一些情况下,动态规划的计算可能会出现数值不稳定的情况,导致结果不准确

  4. 依赖于问题的特征:动态规划的有效性很大程度上依赖于问题的特征,如果问题的特征不满足动态规划的要求,可能需要寻找其他的解决方法。
    在这里插入图片描述

总的来说,动态规划在处理一些具有最优子结构的问题时具有明显的优势,但在处理一些复杂问题时可能会受到限制。在实际应用中,需要根据具体问题的特点来选择合适的算法设计技术。

动态规划在实际问题中的应用

动态规划(Dynamic Programming,DP)是一种常用的算法设计技术,它在解决许多实际问题中都有广泛的应用,以下是一些常见的例子:

  1. 斐波那契数列问题:斐波那契数列是一个经典的动态规划问题,其中每个数都是前两个数的和。动态规划可以高效地计算出斐波那契数列的任意一项

  2. 背包问题:背包问题是一个在资源有限的情况下选择最优物品组合的问题。动态规划可以用来找出在给定背包容量下可获得的最大价值。

  3. 最长公共子序列问题最长公共子序列是两个序列中共同出现的最长子序列。动态规划可以用来找到两个序列的最长公共子序列。

  4. 图像压缩:动态规划可以用于图像压缩,通过将相似的像素块合并为一个代表性的像素块,从而减少图像的存储空间。

  5. 最优路径问题:在图论中,动态规划可以用来找到从一个节点到另一个节点的最短路径或最低成本路径

  6. 资源分配问题:动态规划可以用于资源分配问题,例如在生产计划中,如何在有限的资源下最大化产量。

  7. 字符串匹配问题:动态规划可以用于字符串匹配问题,例如 KMP 算法,它是一种高效的字符串匹配算法。

这些只是动态规划在实际问题中的一些应用,实际上,动态规划可以应用于许多其他领域,如金融、生物学、计算机科学等。动态规划的核心思想是将复杂问题分解为更小的子问题,并通过存储已经计算过的子问题的结果来避免重复计算,从而提高算法的效率。

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

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

相关文章

Android控件全解手册 - 多语言切换完美解决方案(兼容7.0以上版本)

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分…

深入理解OS--硬件高速缓存,缓存一致性,存储设备

存储技术 1.SRAM,DRAM 静态:更快,用作高速缓存存储器。处理器高速缓存采用SRAM。 动态:用作主存及图形系统的帧缓冲区。内存采用DRAM。 2.内存 2.1.内存数据访问示例 设备控制器存在缓存。设备芯片自身存在缓存。 2.2.采用并行…

Spring不再支持Java8了

在今天新建模块的时候发现了没有java8的选项了,结果一查发现在11月24日,Spring不再支持8了,这可怎么办呢?我们可以设置来源为阿里云https://start.aliyun.com/ 。 java8没了 设置URL为阿里云的地址

【Web】NewStarCTF Week3 个人复现

①Include &#x1f350; ?filephpinfo 提示查下register_argc_argv 发现为on LFI包含 pearcmd命令执行学习 pearcmd.php文件包含妙用 ?file/usr/local/lib/php/pearcmd&config-create/<?eval($_POST[a])?>./ha.php ?file./ha post传&#xff1a; asystem…

赛博朋克-MISC-bugku-解题步骤

——CTF解题专栏—— 题目信息&#xff1a; 题目&#xff1a;赛博朋克 作者&#xff1a;Mooooooof 提示&#xff1a; 解题附件&#xff1a; 解题思路&#xff1a; 赛博朋克是个txt文件&#xff1f;&#xff1f;&#xff1f;&#xff0c;不是个game.exe吗&#xff08;开玩笑…

3D场景建模工具

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1. 什么是3D场景建模&#xff1f; 3D场景建模是一种通过计算机图形学技术&#xff0c;将现实世…

如何跑通跨窗口渲染:multipleWindow3dScene

New 这是一个跨窗口渲染的示例&#xff0c;用 Three.js 和 localStorage 在同一源&#xff08;同产品窗口&#xff09;上跨窗口设置 3D 场景。而这也是本周推特和前端圈的一个热点&#xff0c;有不少人在争相模仿它的实现&#xff0c;如果你对跨窗口的渲染有兴趣&#xff0c;可…

pdf文件编辑,[增删改查]

pdf文件是投标文件中必不可少的格式&#xff0c;传统的方式先编辑word格式&#xff0c;最后生成pdf&#xff0c;但是有时候需要直接编辑pdf文件&#xff0c;编辑pdf的工具无疑 “adobe acrobat dc”是最好用的之一了 1.把图片文件添加到pdf指定位置&#xff0c;例如把一张图片添…

zookeeper集群(很少用)+kafka集群(常用)

一、zookeeper zookeeperkafka&#xff08;2.7.0版本&#xff09; kafka&#xff08;3.4.1版本&#xff09;不依赖于zookeeper 1、定义&#xff1a;zookeeper开源&#xff0c;分布式架构&#xff0c;提供协调服务&#xff08;Apache项目&#xff09;&#xff0c;基于观察者模…

【C语言】把歌词里的播放时间跟歌词提取出来

一&#xff0c;介绍 给到一个字符串&#xff0c;里面包含了时间&#xff08;唱该歌词的时间以及该歌词&#xff09;例如“[02:16.33][04:11.44][05:11.44]我想大声宣布对你依依不舍”&#xff0c;如何把两者都给打印出来呢&#xff1f;下面给出解释 二&#xff0c;代码 #incl…

<蓝桥杯软件赛>零基础备赛20周--第8周第1讲--十大排序

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

fastadmin 如何引入自己的js

在需要的界面中&#xff1a;如何实例说明&#xff1a; 中<script> function zhuruJs(url) { let temp document.createElement( script ); temp.setAttribute( type, text/javascript" );temp.src urL; document.head . appendChild(temp); zhuruJs(location…

轻松愉悦的验证方式:实现图片旋转验证功能

说在前面 在当今互联网时代&#xff0c;随着技术的不断进步&#xff0c;传统的验证码验证方式已经无法满足对安全性和用户体验的需求。为了应对日益狡猾的机器人和恶意攻击&#xff0c;许多网站和应用程序开始引入图形验证码&#xff0c;其中一种备受欢迎的形式就是图片旋转验证…

springmvc实验(三)——请求映射

【知识要点】 方法映射概念 所谓的方法映射就是将前端发送的请求地址和后端提供的服务方法进行关联。在springMVC框架中主要使用Controller和RequestMapping两个注解符&#xff0c;实现请求和方法精准匹配。注解符Controller Spring中包含了一个Controller接口&#xff0c;但是…

【C/C++笔试练习】this指针的概念、初始化列表、const对象调用、构造和析构函数、继承和组合、重载和多态、虚函数的定义、计算日期到天数转换、幸运的袋子

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;this指针的概念&#xff08;2&#xff09;初始化列表&#xff08;3&#xff09;const对象调用&#xff08;4&#xff09;构造和析构函数&#xff08;5&#xff09;继承和组合&#xff08;6&#xff09;重载和多态&#x…

七天.NET 8操作SQLite入门到实战 - 第四天EasySQLite前后端项目框架搭建

前言 今天的主要任务是快速下载并安装.NET 8 SDK&#xff0c;搭建EasySQLite的前后端框架。 .NET 8 介绍 .NET 8 是 .NET 7 的后继版本。 它将作为长期支持 (LTS) 版本得到三年的支持。 使用技术栈和开发环境 咱们的.NET 8操作SQLite入门到实战教程主要使用技术栈为如下所示…

Android帝国之进程杀手--lmkd

本文概要 这是Android系统启动的第三篇文章&#xff0c;本文以自述的方式来讲解lmkd进程&#xff0c;通过本文您将了解到lmkd进程在安卓系统中存在的意义&#xff0c;以及它是如何杀进程的。&#xff08;文中的代码是基于android13&#xff09; 我是谁 init&#xff1a;“大…

Java---抽象类讲解

文章目录 1. 抽象类概述2. 抽象类特点3. 抽象类的成员特点4. 抽象类猫狗应用 1. 抽象类概述 在Java中&#xff0c;一个没有方法体的方法应该定义为抽象方法&#xff1b;而类中如果有抽象方法&#xff0c;该类必须定义为抽象类。 2. 抽象类特点 1. 抽象类和抽象方法必须使用abst…

RabbitMQ消息模型之Routing-Topic

Routing Topic Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候使用通配符&#xff01;这种模型Routingkey一般都是由一个或多个单词组成&#xff0c;多个单词之间以”…

vscode非常好用的扩展插件

1、Code Spell Checker&#xff1a; 帮助我们检查单词是否拼写错误&#xff0c;检查规则遵循驼峰拼写法。 2、Color Highlight&#xff1a;高亮显示颜色值 3、Svg Preview&#xff1a; 实时预览svg图片&#xff08;修改width、height、fill等值来实时查看效果&#xff09; 4、…