算法学习笔记(8.1)-动态规划入门

目录

问题特性:

最优子结构:

代码示例:(动态规划最优子结构)

上述最小代价爬楼梯的运行过程:

代码示例:

无后效性:

解析:

具体过程图示如下:

具体的代码示例:

解析:

问题特性:

动态规划的基本是通过子问题分解来求解原问题的。但是通俗来说,子问题分解是一种通用的算法思路,在分治、动态规划、回溯中的侧重点也不同。 

  1. 分治问题:递归地将原问题划分为多个相互独立的子问题,直至最小子问题,并在回溯中合并子问题的解,最终得到原问题的解
  2. 动态规划:对问题进行递归分解,但与分治算法的主要区别是,动态规划中的子问题是相互依赖的,在分解过程中会出现许多重叠的子问题。
  3. 回溯:在尝试和回退中穷举所有的可能的解,并通过剪枝避免不必要的搜索分支。原问题的解由一系列决策步骤构成,我们可以将每个决策步骤之前的子序列看作一个子问题

实际上,动态规划常用来求解最优化问题,它不仅包含重叠子问题,还具有两大特性:最优子结构,无后效性。

最优子结构:

给定一个楼梯,你每步可以上1阶或者2阶,每一个楼梯上都贴有一个非负整数,表示你在该台阶所需要付出的代价。给定一个非负整数数组cost,其中cost[i]表示在第i个台阶需要付出的代价,cost[0]为地面(起始点)。

请计算最少需要付出多少代价才能到达顶部。

若第1,2,3阶的代价分别为1,10,1,则地面爬到第3阶的最小代价为2.

设dp[i]为爬到第i个台阶付出的代价,由于第i阶只能从i-1阶或者i-2阶走来,因此dp[i]只可能等于dp[i-1] + cost[i] 或者 dp[i-2] + cost[i]。为了尽可能减少代价,我们应该选择两者居中较小的那个:

dp[i] = min(dp[i-1],dp[i-2]) + cost[i]

这里就可以直接得出最优字结构的含义:原问题的最优解是从子问题的最优解构建而来。

但是对于爬楼梯的最优子结构,我们又该怎么理解呢,它的目标是求解方案数量,但是我们将其理解称为最大方案数量,虽然题目的含义一样,但是在这里出现了最优子结构的痕迹:第n阶方案最大数量=第n-1阶和第n-2阶最大方案数量和

根据状态转移方程,以及初始状态dp[1] = cost[1]和dp[2] = cost[2]。

代码示例:(动态规划最优子结构)

# python 代码示例
def min_cost_climbing_stairs_dp(cost) :n = len(cost) - 1if n == 1 or n == 2 :return cost[n]dp = [0] * (n + 1)dp[1], dp[2] = cost[1], cost[2]for i in range(3, n + 1) :dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]return dp[n]
// c++ 代码示例
int minCostClimbingStairsDP(vector<int> &cost)
{int n = cost.size() - 1 ;if (n == 1 || n == 2){return cost[n] ;}vector<int> dp(n + 1) ;dp[1] = cost[1] ;dp[2] = cost[2] ;for (int i = 3; i <= n ; i++){dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] ;}return dp[n] ;
}

上述最小代价爬楼梯的运行过程:

将上述代码进行空间优化,将一维压缩至0维,空间复杂度由O(n)变为O(1)

代码示例:

# python 代码示例
def min_cost_climbing_stairs_dp_comp(cost) :n = len(cost) - 1if n == 1 or n == 2 :return cost[n]a, b = cost[1], cost[2]for i in range(3, n + 1) :a, b = b, min(a, b) + cost[i]return b
// c++ 代码示例
int minCostClimbingStairsDPComp(vector<int> &cost)
{int n = cost.size() - 1 ;if (n == 1 || n == 2){return cost[n] ;}int a = cost[1], b = cost[2] ;for (int i = 3 ; i <= n ; i++){int temp = b ;b = min(a, b) + cost[i] ;a = temp ;}return b ;
}

无后效性:

能够有效解决问题的重要特性之一,定义:给定一个确定的状态,它的未来发展只与当前的状态有关,而与过去经历的所有状态无关。

以爬楼梯进行相关理解,给定状态i,它会发展出状态i+1和状态i+2,分别对应跳1步和跳2步。在做出这两种选择时,无须考虑状态i之前的状态,它们对i的未来没有影响。

但是下面这种情况就不一样了:如题,给定一个共有n阶的楼梯,你每一步可以上1阶或者2阶,但是不能连续两次跳1阶,请问有多少种方案可以爬到楼顶?

如图所示:爬3阶的例子

解析:

如果上一轮跳1阶上来的,下一次跳动必须跳2阶。这就意味着,下一步的选择不能由当前状态(当前所在楼梯阶数)独立决定,还和前一个状态(上一轮的楼梯的阶数)有关。

所以原来的状态转移方程dp[i] = dp[i-1] + dp[i-2]也因此失效,为了满足约束条件,我们不能直接将dp[i-1]直接放入到dp[i]中。

为此,我们需要扩展状态定义:状态[i,j]表示处在第i阶并且上一轮跳了j阶,其中j属于{1,2}。此状态定义有效地区分了上一轮跳了1阶还是2阶,我们可以根据判断当前状态从何而来。

  1. 当上一轮跳了1阶时,上上一轮只能选择跳2阶,即dp[i,1]只能从dp[i-1,2]转移过来
  2. 当上一轮跳了2阶时,上上一轮可选择跳1阶或者跳2阶,即dp[i,2]可以从dp[i-2,1]或dp[i-2,2]转移过来。

因此,在该定义下,dp[i,j]表示状态[i,j]对应的方案数。状态转移方程为:

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

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

具体过程图示如下:

最终,返回dp[n,1] + dp[n,2]即可,两者之和代表爬到第n阶的方案总数:

具体的代码示例:

# python 代码示例
def climbing_stairs_constraint_dp(n) :if n == 1 or n == 2 :return 1dp = [ [0] * 3 for _ in range(n + 1)]dp[1][1], dp[1][2] = 1, 0dp[2][1], dp[2][2] = 0, 1for i in range(3, n + 1) :dp[i][1] = dp[i - 1][2]dp[i][2] = dp[i - 2][1] + dp[i - 2][2]return dp[n][1] + dp[n][2]
// c++ 代码示例
int climbingStairsConstraintDP(int n)
{if (n == 1 || n == 2){return 1 ;}vector<vector<int>> dp(n + 1, vector<int>(3, 0)) ;dp[1][1] = 1 ;dp[1][2] = 0 ;dp[2][1] = 0 ;dp[2][2] = 1 ;for (int i = 3 ; i <= n ; i++){dp[i][1] = dp[i - 1][2] ;dp[i][2] = dp[i - 2][1] + dp[i - 2][2] ;}return dp[n][1] + dp[n][2] ;
}

解析:

在上面的约束条件中只需要考虑一个约束对象,因此我们可以通过扩展状态定义,使得问题重新满足无后效性,

给定一个共有 i 阶的楼梯,你每步可以上 1 阶或者 2 阶。规定当爬到第 i 阶时,系统自动会在第 2i 阶上放上障碍物,之后所有轮都不允许跳到第 2i 阶上。例如,前两轮分别跳到了第 2、3 阶上,则之后就不能跳到第 4、6 阶上。请问有多少种方案可以爬到楼顶?

在这个问题中,下次跳跃依赖过去所有的状态,因为每一次跳跃都会在更高的阶梯上设置障碍,并影响未来的跳跃。对于这类问题,动态规划往往难以解决。

实际上,许多复杂的组合优化问题(例如旅行商问题)不满足无后效性。对于这类问题,我们通常会选择使用其他方法,例如启发式搜索、遗传算法、强化学习等,从而在有限时间内得到可用的局部最优解。

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

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

相关文章

如何为IP申请SSL证书

目录 以下是如何轻松为IP地址申请SSL证书的详细步骤&#xff1a; 申请IP证书的基本条件&#xff1a; 申请IP SSL证书的方式&#xff1a; 确保网络通信安全的核心要素之一&#xff0c;是有效利用SSL证书来加密数据传输&#xff0c;特别是对于那些直接通过IP地址访问的资源。I…

使用 Azure DevOps Pipelines 生成 .NET Core WebJob 控制台应用 CI/CD

Web 应用程序通常需要作为后台任务运行的进程&#xff0c;并在特定时间间隔进行计划或在事件中触发。它们不需要花哨的 IO 接口&#xff0c;因为重点是过程而不是输出。Azure WebJobs 提供了出色的支持&#xff0c;通常在云环境中通过 Web 控制台应用程序来实现此目的。WebJob …

企业数字化转型中的低代码开发平台应用:释放创新潜能

随着信息技术的飞速发展&#xff0c;企业数字化转型已成为行业趋势。在这场转型浪潮中&#xff0c;低代码开发平台以其独特的优势&#xff0c;成为众多企业实现快速迭代、高效创新的得力助手。本文将深入探讨低代码开发平台在企业数字化转型中的应用&#xff0c;以及如何帮助企…

Mac平台虚拟机 Parallels Desktop v19.4.1,支持M1/M2/M3芯片组

Parallels Desktop for Mac是功能强大灵活度高的虚拟化方案&#xff0c;无需重启即可在同一台电脑上随时访问Windows和Mac两个系统上的众多应用程序。从仅限于PC的游戏到生产力软件&#xff0c;Parallels Desktop都能帮您实现便捷使用。Parallels Desktop 是一款专业的Mac虚拟机…

Docker搭建kafka+zookeeper以及Springboot集成kafka快速入门

参考文章 【Docker安装部署KafkaZookeeper详细教程】_linux arm docker安装kafka-CSDN博客 Docker搭建kafkazookeeper 打开我们的docker的镜像源配置 vim /etc/docker/daemon.json 配置 { "registry-mirrors": ["https://widlhm9p.mirror.aliyuncs.com"…

vue父子组件通信实现模糊搜索功能

我遇到的问题&#xff1a; 我的搜索框在父页面&#xff0c;静态数据都在子页面。怎么实现模糊查询数据&#xff1f; 昨天的尝试&#xff1a;先把搜索的内容数据存到session里&#xff0c;然后从session里拿&#xff0c; 结果&#xff1a;存是存进去了&#xff0c;却拿不到。应…

Django学习收尾

启动项目命令 python manage.py runserver 文件上传功能实现 title "Form上传"if request.method "GET":form UpForm()return render(request, upload_form.html, {"form": form, "title": title})form UpForm(datarequest.POS…

Java对象创建究竟是在栈上还是堆上??

在 Java 中&#xff0c;对象的创建通常情况下是在堆上。 基本数据类型&#xff08;如 byte、short、int、long、float、double、char&#xff09;在方法内声明时&#xff0c;其值会存储在栈上。除了基本数据类型之外的所有对象&#xff0c;都是由 Java 虚拟机&#xff08;JVM&…

python入门基础知识·二

""" # Python介绍 # Python注释 # 单行注释&#xff1a; # # 多行注释&#xff1a; r """""" # Python输出和输入 # print: 输出 # input: 输入 ①会让程序暂停&#xff0c;②得到的是字符串内容 int(&…

Linux Mac 安装Higress 平替 Spring Cloud Gateway

Linux Mac 安装Higress 平替 Spring Cloud Gateway Higress是什么?传统网关分类Higress定位下载安装包执行安装命令执行脚本 安装成功打开管理界面使用方法configure.shreset.shstartup.shshutdown.shstatus.shlogs.sh Higress官网 Higress是什么? Higress是基于阿里内部的…

Vue指令详解与实操运用 - 编程魔法

在Vue.js的世界里&#xff0c;指令就像是一位魔法师&#xff0c;它们能够赋予HTML元素以生命&#xff0c;让网页与用户互动起来。今天&#xff0c;我们就来揭开这些指令的神秘面纱&#xff0c;看看它们是如何在我们的日常开发中发挥作用的。 1. v-text 和 v-html - 文字与内容的…

思考:Java内存模型和硬件内存模型

前言 前一阵在看volatile的原理&#xff0c;看到内存屏障和缓存一致性&#xff0c;发现再往底层挖就挖到了硬件和Java内存模型。这一块是自己似懂非懂的知识区&#xff0c;我一般称之为知识混沌区。因此整理这一篇文章。 什么是内存模型&#xff08;Memory Model&#xff09;…

CentOS6用文件配置IP模板

CentOS6用文件配置IP模板 到 CentOS6.9 , 默认还不能用 systemctl , 能用 service chkconfig sshd on 对应 systemctl enable sshd 启用,开机启动该服务 ### chkconfig sshd on 对应 systemctl enable sshd 启用,开机启动该服务 sudo chkconfig sshd onservice sshd start …

未羽研发测试管理平台

突然有一些觉悟&#xff0c;程序猿不能只会吭哧吭哧的低头做事&#xff0c;应该学会怎么去展示自己&#xff0c;怎么去宣传自己&#xff0c;怎么把自己想做的事表述清楚。 于是&#xff0c;这两天一直在整理自己的作品&#xff0c;也为接下来的找工作多做点准备。接下来…

LT7911UX 国产原装 一拖三 edp 转LVDS 可旋转 可缩放

2.一般说明 该LT7911UX是一种高性能Type-C/DP1.4a到MIPI或LVDS芯片的VR/显示应用。HDCP RX作为HDCP转发器的上游&#xff0c;可以与其他芯片的HDCP TX配合实现转发器功能。 对于DP1.4a输入&#xff0c;LT7911UX可配置为1/2/4通道。自适应均衡使其适用于长电缆应用&#xff0c;最…

Junior.Crypt.2024 CTF Web方向 题解WirteUp 全

Buy a cat 题目描述&#xff1a;Buy a cat 开题 第一思路是抓包改包 Very Secure App 题目描述&#xff1a;All secrets become clear 开题 乱输一个密码就登陆成功了&#xff08;不是弱口令&#xff09; 但是回显Your role is: user 但是有jwt&#xff01;&#xff01;&a…

深入理解基本数据结构:链表详解

引言 在计算机科学中&#xff0c;数据结构是存储、组织和管理数据的方式。链表是一种重要的线性数据结构&#xff0c;广泛应用于各种编程场景。在这篇博客中&#xff0c;我们将详细探讨链表的定义、特点、操作及其在不同编程语言中的实现。 什么是链表&#xff1f; 链表是一种…

Mobile ALOHA前传之VINN, Diffusion Policy和ACT对比

VINNDiffusion PolicyACT核心思想1.从离线数据中自监督学习获得一个视觉编码器&#xff1b;2.基于视觉编码器&#xff0c;从采集的示例操作数据中检索与当前观测图像最相似的N张图像以及对应的动作&#xff1b;3.基于图像编码器的距离对各个动作进行加权平均&#xff0c;获得最…

Open3D loss函数优化的ICP配准算法(精配准)

目录 一、概述 1.1ICP的基本步骤 1.2损失函数的设计 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始点云 3.2配准后点云 3.3计算数据 一、概述 ICP(Iterative Closest Point)配准算法是一种用于对齐两个点云的经典算法。其目标是通过迭代优化…

Istio实战教程:Service Mesh部署与流量管理

引言 Istio是一个开源的服务网格&#xff0c;它提供了一种统一的方法来连接、保护、控制和观察服务。本教程将指导你从零开始部署Istio&#xff0c;并展示如何使用Istio进行基本的流量管理。 环境准备 Kubernetes集群&#xff1a;Istio运行在Kubernetes之上&#xff0c;确保…