算法(四)——动态规划

文章目录

    • 基本思想
    • 适用条件
      • 最优子结构
      • 子问题重叠
      • 状态转移方程
    • 解题步骤
    • 应用
      • 斐波那契数列
      • 背包问题
      • 最大子数组和

基本思想

动态规划的核心思想在于将一个复杂的问题分解为一系列相互关联的子问题,通过求解子问题并保存其解,避免对相同子问题的重复计算,从而提高算法的效率。具体来说,动态规划通常会利用已经解决的子问题的结果来推导出更大规模子问题的解,直至最终解决原问题。

适用条件

最优子结构

问题的最优解包含其子问题的最优解。也就是说,一个问题的最优解可以由其子问题的最优解组合而成。例如,在求解最短路径问题时,从起点到终点的最短路径必然包含从起点到中间某个节点的最短路径。

子问题重叠

在求解问题的过程中,会多次遇到相同的子问题。通过保存这些子问题的解,避免重复计算,从而提高算法的效率。例如,在斐波那契数列的计算中,计算较大的斐波那契数时会多次用到较小的斐波那契数。

状态转移方程

用于描述问题的状态和状态之间的关系,通过状态的转移得到最终问题的解。

解题步骤

定义状态:确定问题的状态表示,即如何用一个或多个变量来描述问题的子问题。状态的定义需要能够准确地刻画问题的特征,并且要满足最优子结构性质。

找出状态转移方程:根据问题的最优子结构性质,找出状态之间的递推关系,即如何从已知的子问题的解推导出当前问题的解。状态转移方程是动态规划算法的核心。

确定初始状态:找出问题的边界条件,即最简单的子问题的解。初始状态是递推的起点,后续的状态都是基于初始状态逐步推导出来的。

计算顺序:根据状态转移方程,确定状态的计算顺序。通常有两种计算顺序:自顶向下(记忆化搜索)和自底向上(迭代)。自顶向下方法从原问题出发,递归地求解子问题,并保存已经求解的子问题的解;自底向上方法则从初始状态开始,逐步计算出所有子问题的解,直到得到原问题的解。

返回结果:根据问题的要求,从计算得到的状态中提取出最终的解。

应用

斐波那契数列

 public class Fibonacci {public static int fibonacci(int n) {    if (n <= 1) return n;        int[] dp = new int[n + 1];       dp[0] = 0;        dp[1] = 1;        for (int i = 2; i <= n; i++) {            dp[i] = dp[i - 1] + dp[i - 2];       }        return dp[n];    }   public static void main(String[] args) {                       System.out.println(fibonacci(10));  }}
  • 子问题定义:定义 dp[i] 表示第 i 个斐波那契数。
  • 状态转移方程: dp[i] = dp[i - 1] + dp[i - 2] ,其中 i >= 2 , dp[0] = 0 , dp[1] = 1 。- 时间复杂度:使用了一个循环来计算 dp 数组的每个元素,循环次数为 n ,因此时间复杂度为 O(n) 。
  • 空间复杂度:使用了一个大小为 n + 1 的数组 dp 来存储子问题的解,所以空间复杂度为 O(n)。
  • 实际上,由于计算 dp[i] 时只需要 dp[i - 1] 和 dp[i - 2] 的值,我们可以进一步优化空间复杂度到 ,只使用两个变量来存储前两个斐波那契数。

背包问题

 public class Knapsack {public static int knapsack(int[] weights, int[] values, int capacity) {        int n = weights.length;        int[][] dp = new int[n + 1][capacity + 1];        for (int i = 1; i <= n; i++) {            for (int j = 1; j <= capacity; j++) {                if (weights[i - 1] <= j) {                    dp[i][j] = Math.max(values[i - 1] + dp[i - 1][j - weights[i - 1]], dp[i - 1][j]);                } else {                    dp[i][j] = dp[i - 1][j];               }            }      }        return dp[n][capacity];    }    public static void main(String[] args) {        int[] weights = {2, 3, 4, 5};        int[] values = {3, 4, 5, 6};        int capacity = 8;        System.out.println(knapsack(weights, values, capacity));    }}
  • 子问题定义:定义 dp[i][j] 表示在前 i 个物品中选择,且背包容量为 j 时能获得的最大价值。
  • 状态转移方程:
    • 当 weights[i - 1] <= j 时(即第 i 个物品可以放入背包), dp[i][j] = Math.max(values[i - 1] + dp[i - 1][j - weights[i - 1]], dp[i - 1][j]) ,表示取放入第 i 个物品和不放入第 i 个物品两种情况的较大值。
    • 当 weights[i - 1] > j 时(即第 i 个物品放不下), dp[i][j] = dp[i - 1][j] ,即不放入第 i 个物品。
  • 时间复杂度:有两个嵌套的循环,外层循环遍历物品数量 n 次,内层循环遍历背包容量 capacity 次,所以时间复杂度为 O(n×capacity) 。
  • 空间复杂度:使用了一个二维数组 dp[n + 1][capacity + 1] 来存储子问题的解,因此空间复杂度为O(n×capacity) 。通过优化,可以将空间复杂度降低到 ,因为每次计算 dp[i][j] 时只依赖于 dp[i - 1][…] 的值。

最大子数组和

假设有一个数组 nums,求解其连续子数组的最大和

  • 定义状态: 设 dp[i] 为以 nums[i] 结尾的连续子数组的最大和。
  • 状态转移方程: dp[i] = max(dp[i-1] + nums[i], nums[i]),即当前位置的最大和要么是之前的最大和加上当前元素,要么是当前元素本身。
  • 初始化: dp[0] = nums[0],数组的第一个元素作为初始值。
  • 遍历: 从数组的第二个元素开始遍历,更新 dp[i]。
  • 最终结果: 最大的 dp[i] 即为所求。
public class MaxSubarraySum {public static int maxSubarraySum(int[] nums) {int n = nums.length;// 创建一个数组 dp 用于保存子问题的解int[] dp = new int[n];// 初始化 dp 数组的第一个元素dp[0] = nums[0];// 遍历数组,根据状态转移方程更新 dp 数组for (int i = 1; i < n; i++) {dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);}// 找出 dp 数组中的最大值int max = dp[0];for (int i = 1; i < n; i++) {if (dp[i] > max) {max = dp[i];}}return max;}public static void main(String[] args) {int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};int result = maxSubarraySum(nums);System.out.println(result); // 输出 6,对应子数组 [4, -1, 2, 1]}
}

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

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

相关文章

基于Nanopi duo2的WiFi智能摄像头

1.固件包烧录 https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo2/zh#.E8.BF.9E.E6.8E.A5WiFi 固件包链接以及烧录工具都在上面链接中 烧录过程 使用读卡器将SD卡插入到电脑,然后打开烧录工具 2.通过串口工具连接板子使其连接WiFi 对应的串口工具,就是这个HyperT…

单片机延时函数怎么写规范?

我们以前在开发产品的时候&#xff0c;肯定会碰到一些延时需求&#xff0c;比如常见的LED闪烁&#xff0c;按键消抖&#xff0c;控制IO口输出时序等等。 别小看延时&#xff0c;这个小问题&#xff0c;想做好&#xff0c;甚至要考虑到程序架构层面。 在开发板上&#xff0c;可能…

Dify私有化部署自己的AI Agent

1、下载Dify git clone gitgithub.com:langgenius/dify.git 2、创建Dify配置 进入dify目录下的docker目录中,复制.env.example为 .env 3、使用Docker命令进行部署Dify docker compose up -d 4、访问Dify http://localhost/install 5、 设置模型供应商 配置环境变量&#xff1…

【Unity】鱼群效果模拟

鱼群效果模拟 文章目录 鱼群效果模拟Boid算法实现方式version1_CPUversion2_GPUversion3_Multilaterationversion4_Bitonic_Sorting &#xff08;GPU友好&#xff09;version5_Skinning &#xff08;TODO&#xff09; 细节项优化项参考链接 Boid算法 Boid算法是一种模拟群体行…

【AI时代】可视化训练模型工具LLaMA-Factory安装与使用

文章目录 安装训练使用 安装 官方地址&#xff1a;https://github.com/hiyouga/LLaMA-Factory 创建虚拟环境 conda create -n llama-factory conda activate llama-factory安装 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip in…

tailwindcss学习03

01 入门 02 vue中接入 03 工具类优先 准备 vue.svg <svg viewBox"0 0 40 40" xmlns"http://www.w3.org/2000/svg"> <defs> <linearGradient x1"50%" y1"0%" x2"50%" y2"100%" id"a"&…

Java 笔记(自用)

Java是一种面向对象(opp)的、解释性的跨平台语言。所谓的跨平台是Java的一个编译好的.class文件可以在多个系统下运行。解释性则是编译后的代码需要解释器来执行&#xff0c;与之相对应的c/c是编译性语言&#xff0c;编译后的代码可以直接被机器执行。 jdkjrejava的开发工具 …

Matlab——图像保存导出成好看的.pdf格式文件

点击图像的右上角&#xff0c;点击第一个保存按钮键。

游戏引擎学习第120天

仓库:https://gitee.com/mrxiao_com/2d_game_3 上次回顾&#xff1a;周期计数代码 我们正在进行一个项目的代码优化工作&#xff0c;目标是提高性能。当前正在优化某个特定的代码片段&#xff0c;已经将其执行周期减少到48个周期。为了实现这一目标&#xff0c;我们设计了一个…

大语言模型微调的公开JSON数据

大语言模型微调的公开JSON数据 以下是一些可用于大语言模型微调的公开JSON数据及地址: EmoLLM数据集 介绍:EmoLLM是一系列能够支持理解用户、帮助用户心理健康辅导链路的心理健康大模型,其开源了数据集、微调方法、训练方法及脚本等。数据集按用处分为general和role-play两种…

20分钟 Bash 上手指南

文章目录 bash 概念与学习目的第一个 bash 脚本bash 语法变量的使用位置参数管道符号&#xff08;过滤条件&#xff09;重定向符号条件测试命令条件语句case 条件分支Arrayfor 循环函数exit 关键字 bash 脚本记录历史命令查询文件分发内容 bash 概念与学习目的 bash&#xff0…

《Python实战进阶》专栏 No.3:Django 项目结构解析与入门DEMO

《Python实战进阶》专栏 第3集&#xff1a;Django 项目结构解析与入门DEMO 在本集中&#xff0c;我们将深入探讨 Django 的项目结构&#xff0c;并实际配置并运行一个入门DEMO博客网站&#xff0c;帮助你在 Web 开发中更高效地使用 Django。Django 是一个功能强大的 Python Web…

Spring Boot 应用(官网文档解读)

Spring Boot 启动方式 SpringApplication.run(MyApplication.class, args); Spring Boot 故障分析器 在Spring Boot 项目启动发生错误的时候&#xff0c;我们通常可以看到上面的内容&#xff0c;即 APPLICATION FAILED TO START&#xff0c;以及后面的错误描述。这个功能是通过…

win32汇编环境,对话框中使用菜单示例三

;运行效果 ;win32汇编环境,对话框中使用菜单示例三 ;鼠标点击右键时&#xff0c;弹出菜单的功能 ;直接抄进RadAsm可编译运行。重要部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>>&g…

stm32-电源控制

STM32 的 PWR&#xff08;Power Control&#xff09;外设 是用于管理微控制器电源模式和外设电源控制的模块。通过 PWR 外设&#xff0c;可以实现低功耗模式、电压调节、备份域控制等功能&#xff0c;从而优化系统的功耗和性能。 stm32内部电源框图 电源区域 VDD 供电区&#x…

云计算及其他计算

云计算知识思维导图&#xff1a;https://kdocs.cn/l/cpl2Kizx7IyC 云计算的核心判断标准通常基于美国国家标准与技术研究院&#xff08;NIST&#xff09;的定义&#xff0c;并结合实际应用场景。以下是判断一个服务是否为云计算的关键标准&#xff0c;以及对应的服务类型&#…

mysql之B+ 树索引 (InnoDB 存储引擎)机制

b树索引机制 B 树索引 (InnoDB 存储引擎)机制**引言&#xff1a;****1. 数据页结构与查找**2. 索引的引入**3. InnoDB 的 B 树索引****4. InnoDB B 树索引的注意事项****5. MyISAM 的索引方案 (选读&#xff0c;与 InnoDB 做对比)****6. MySQL 中创建和删除索引的语句** **B 树…

量子计算驱动的金融衍生品定价革命:突破传统蒙特卡洛模拟的性能边界

引言&#xff1a;金融计算的算力困局 某国际投行采用128量子位处理器对亚洲期权组合定价时&#xff0c;其量子振幅估计算法在2.7秒内完成传统GPU集群需要68小时的计算任务。在蒙特卡洛路径模拟实验中&#xff0c;量子随机游走算法将10,000维衍生品的价格收敛速度提升4个数量级…

Web刷题之PolarDN(中等)

1.到底给不给flag呢 代码审计 一道典型的php变量覆盖漏洞 相关知识 什么是变量覆盖漏洞 自定义的参数值替换原有变量值的情况称为变量覆盖漏洞 经常导致变量覆盖漏洞场景有&#xff1a;$$使用不当&#xff0c;extract()函数使用不当&#xff0c;parse_str()函数使用不当&…

ShenNiusModularity项目源码学习(12:ShenNius.Common项目分析)

ShenNius.Common项目中主要定义功能性的辅助函数类及通用类&#xff0c;供MVC模式、前后端分离模式下的后台服务使用&#xff0c;以提高编程效率。   ApiResult文件内的ApiResult和ApiResult类定义了通用的数据返回格式&#xff0c;包括状态码、返回消息、返回数据等&#x…