python 基础知识点(蓝桥杯python科目个人复习计划41)

今日复习内容:动态规划(基础)

动态规划是一种解决多阶段决策过程中最优化问题的数学方法和算法思想。它通常用于解决具有重叠子问题和最优子结构性质的问题,通常将问题划分为相互重叠的子问题,利用子问题的解来求解原问题。

动态规划算法通常包括以下几个关键要素:

(1)最优子结构:指问题的最优解可以通过子问题的最优解来构造。换句话说,问题的整体最优解可以通过子问题的最优解递归地求解而得到。

(2)重叠子问题:指在求解问题的过程中,需要多次解决相同的子问题。为了避免重复计算,动态规划算法通常采用记忆化搜索或者自下而上的方式来保存子问题的解,从而提高效率。

(3)状态转移方程:描述了问题从一个阶段转移到下一个阶段的递推关系,通过定义合适的状态以及状态之间的转移关系,可以将问题分解成更小的子问题,并利用这些子问题的解来解决原问题。

(4)初始化条件:确定问题的初始状态,即最小问题的子问题的解。通常需要初始化一个表格或者数组来存储子问题的解,并设置初始状态的值。

(5)递推求解:根据状态转移方程,递归地求解问题的每个阶段,直到达到问题的最终目标。

动态规划算法常用于求解诸如最长公共子序列,最短路径,背包问题等优化问题。它的核心思想是将复杂问题分解成简单的子问题,并利用子问题的解来构造原问题的解,从而实现对问题的高效求解。


我一直没搞懂什么是“状态转移”,所以我就去搜了一下。

接下来我以斐波那契数列为例来说明动态规划的状态转移过程。

斐波那契数列是一个经典的递归序列,定义如下:

斐波那契数列的每一项都是前两项的和。

现在,我来使用动态规划算法来求解斐波那契数列。在这个过程中,我将定义状态转移方程来描述问题的解决过程。

将斐波那契数列的第n项定义为dp[n],则状态转移方程可以定义为:

根据这个状态转移方程,可以通过递推关系从前两项的值推出后面的项的值,直到达到目标项的位置。

OK,接下来我把它编成代码:

def fun(n):if n == 0:return 0if n == 1:return 1dp = [0] * (n + 1)dp[0] = 0dp[1] = 1for i in range(2,n + 1):dp[i] = dp[i - 1] + dp[i - 2]return dp[n]print(fun(2))

运行结果:

在这个例子中,我使用了动态规划算法来计算斐波那契数列的第n项,通过递推关系

dp[i] = dp[i - 1] + dp[i - 2],就可以推导出来了。


 dp[i] = dp[i - 1] + dp[i - 2]  这个就是动态规划中的一个重要推导式。

我来推导一下:

比如一个人上楼梯,规定一次可以走1步,也可以走两步,当他从第一级阶梯走到第级阶梯的时候,走到步数情况如下:

从第一级走到第二级:1

从第一级走到第三级:1 + 1,2

从第二级走到第四级:1 + 1,2

从第三级走到第四级:1

从第一级走到第四级:1 + 1 + 1,1 + 2,2 + 1

然后看我写的最后三行,以第四级为基准,记为i,则从第三级到第四级(跨度为1)就是i - 1,从第二级到第四级(跨度为2)就是i - 2,那么从我推的数据来看,1 + 1 + 1 = 1 + 1 + 1,1 + 2 = 1 + 2,1 + 2 = 2 + 1。

搞定,这就是我的推导过程。

做个题:

例题:破损的楼梯

题目描述:

小蓝来到了一座高耸的楼梯前,楼梯共有N级台阶,从第0级台阶出发,小蓝每次可以迈上1级或2级台阶。但是,楼梯上的第ai级,第a2级,...,以此类推,共有M级台阶的台阶面坏了,不能踩上去。

现在,小蓝想要到达楼梯的顶端,也就是第N级台阶,但他不能踩到坏了的台阶。请问他有多少种步踩到坏了的台阶但是能到达顶端的方案数。

由于方案数很大,请输出其对10^9 + 7取模。

输入格式:

第一行包含两个正整数N(1 <= N <= 10^5)和M(0 <= M <= N),表示楼梯的总级数和坏了的台阶数。

接下来一行,包含M哥正整数a1,a2,...,aM(1 <= a1 < a2 < a3 < ... < aM <= N),表示坏掉的台阶的编号。

输出格式:

输出一个整数,表示小蓝到达楼梯顶端的方案数,对10^9 + 7取模。

思路:

这个题的原型就是我上面推导的代码,它只是加了一个“有坏台阶”的约束条件。

参考答案:

N,M = map(int,input().split())
a = list(map(int,input().split()))
vis = [0]*(N + 1)
dp = [0]*(N + 1)
for x in a:vis[x] = 1dp[0] = 1
dp[1] = 1 - vis[1]for i in range(2,N + 1):if vis[i] == 1:continuedp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007print(dp[N])

运行结果:

 


以上是一维的,接下来我来分析二维的。

动态规划是一种常用的算法设计技巧,用于解决具有重叠子问题和最优子结构性质的问题。二维动态规划是动态规划中的一种形式,适用于解决二维状态的问题。

在二维动态规划中,我们通常使用一个二维数组来存储子问题的解。这个二维数组的每个元素通常表示一个状态,而状态之间的转移则通过状态转移方程来描述。二维DP通常适用于具有二维状态的问题,比如矩阵,网格等。

下面是二维动态规划的一般步骤:

(1)定义状态:首先确定问题的状态,即确定二维DP数组的含义。这通常涉及到问题的规模和限制条件。状态的定义应该能够唯一地描述问题的局部情况。

(2)状态转移方程:接下来确定状态之间的转移关系,也就是状态转移方程。状态转移方程描述了如何从一个状态转移到下一个状态,并且通常是问题的核心。通过状态转移方程,我们可以将原问题划分成若干个子问题,从而利用子问题的解来求解原问题。

(3)初始化:对DP数组进行初始化。初始化通常是为了处理边界情况或一些特殊情况,使得DP数组的初始状态满足状态转移方程。

(4)状态转移:通过状态转移方程,从初始状态开始逐步更新DP数组,直到达到目标状态。

(5)求解目标:最终,根据问题的要求,确定DP数组中哪些状态对应着我们需要的结果。


这么说太抽象了,我来举个例子,解释一下这个过程。

问题:在一个二维网格中,从左上角到右下角有多少条不同的路径?每次只能向右或向下移动。

(1)定义状态:令dp[i][j]表示从起点到达网格中坐标为(i,j)的位置的不同路径数。

(2)状态转移方程:对于网格中的每个位置(i,j),可以从左边位置(i - 1,j)或者上方位置(i,j - 1)到达,因此状态转移方程为dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。

(这个左边和上方坐标怎么来的,我以前的文章解释过两次,可以去参考一下)

(3)初始化:对于网格的第一行和第一列,由于只能向右或向下移动,因此到达这些位置的路径数都为1,所以初始化为1。

(4)状态转移:从左上角开始逐步更新dp数组,根据状态转移方程进行状态转移。

(5)求解目标:最终,dp[m - 1][n - 1]即为从左上角到右下角的不同路径数。

二维动态规划是动态规划中的重要形式之一,它使用于许多实际问题的求解,如最长公共子序列,最长递增子序列,矩阵路径等。通过合理定义状态和状态转移方程,我们可以高效解决许多复杂问题。


OK,我现在的头脑无比清晰,来做个题吧。

例题1:矩阵中的最长递增路径

题目描述:

给定一个整数矩阵,找出最长递增路径 的长度。对于每个单元格,你可以从当前单元格向上,向下,向左,向右移动,但不能移动到边界外(即不允许环绕)。

示例:

输入:
[
  [9,9,4],
  [6,6,8],
  [2,1,1]

输出: 4 
解释: 最长递增路径为 [1, 2, 6, 9]。
解题思路:

(1)定义状态:定义一个二维dp数组,其中dp[i][j]表示以(i,j)为起点的最长递增路径的长度。

(2)状态转移方程:对于每个位置(i,j),可以向上,向下,向左,向右四个方向移动,如果相邻位置的值大于当前位置,则可以移动到相邻位置。因此,状态转移方程为

dp[i][j] = max(dp[i][j],1 + dp[x][y]),其中(x,y)为相邻位置且大于(i,j)的位置。

(3)初始化:将dp数组所有元素初始化为1,因此最短路径长度至少为1。

(4)状态转移:从左上角开始遍历矩阵,对每个位置(i,j),根据状态转移方程更新dp[i][j]。

(5)求解目标:遍历整个dp数组,找出最大值即为最长递增路径的长度。


接下来一步一步写代码:

(1)函数定义:

def longestpath(a):

这里我定义了一个名为longestpath的函数 ,它接受一个二维整数矩阵a作为输入

(2)边界情况处理:

    if not a:return 0

如果输入的矩阵a为空,即没有任何元素,那么直接返回0,表示最长递增路径的长度为0.

(3)矩阵行数和列数获取:

r,c = len(a),len(a[0])

获取输入矩阵的行数和列数,以便后续的遍历和处理。

(4) dp数组的初始化

 dp = [[1]*c for _ in range(r)]

创建一个与输入矩阵 相同大小的二维数组dp,并将所有元素初始化为1.这里dp[i][j]表示以(i,j)为起点的最长递增路径的长度,初始值设为1,表示最短路径长度为1。

(5)深度优先搜索(DFS)函数定义

 def dfs(i,j):if dp[i][j] != 1:return dp[i][j]directions = [(0,1),(0,-1),(1,0),(-1,0)]for dx,dy in directions:x,y = i + dx,j + dyif 0 <= x < r and 0 <= y < c and a[x][y] > a[i][j]:dp[i][j] = max(dp[i][j],1 + dfs(x,y))return dp[i][j]

这里我用的是搜索法,用于在矩阵中查找最长递增路径,它接受两个参数i和j,表示当前位置的行和列。首先检查是否已经计算过(i,j)位置的最长递增路径长度,如果已经计算过,则直接返回结果;否则,尝试向四个方向进行移动,并更新dp[i][j]的值。

(6)全局最长路径变量的初始化

result = 0

初始化一个变量result,用于记录全局最长递增路径的长度。

(7) 矩阵变量及结果更新

 for i in range(r):for j in range(c):result = max(result,dfs(i,j))

遍历整个矩阵,对每个位置(i,j),调用深度优先搜索函数dfs(i,j) ,并与返回的结果result比较,保留较大值作为全局最长路径的长度。

(8)返回结果

return result

返回全局最长递增路径的长度作为函数的输出结果。


OK,现在我把它完整的写出来。

def longestpath(a):if not a:return 0r,c = len(a),len(a[0])dp = [[1]*c for _ in range(r)]def dfs(i,j):if dp[i][j] != 1:return dp[i][j]directions = [(0,1),(0,-1),(1,0),(-1,0)]for dx,dy in directions:x,y = i + dx,j + dyif 0 <= x < r and 0 <= y < c and a[x][y] > a[i][j]:dp[i][j] = max(dp[i][j],1 + dfs(x,y))return dp[i][j]result = 0for i in range(r):for j in range(c):result = max(result,dfs(i,j))return resulta = [[9, 9, 4],[6, 6, 8],[2, 1, 1]
]
print(longestpath(a))

运行结果:

 

答案是正确的。

经过我的不懈努力,我终于会一点动态规划了!

OK,这篇就写到这里,下一篇继续! 

 

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

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

相关文章

Git分支和迭代流程

Git分支 feature分支&#xff1a;功能分支 dev分支&#xff1a;开发分支 test分支&#xff1a;测试分支 master分支&#xff1a;生产环境分支 hotfix分支&#xff1a;bug修复分支。从master拉取&#xff0c;修复并测试完成merge回master和dev。 某些团队可能还会有 reale…

移动机器人激光SLAM导航(五):Cartographer SLAM 篇

参考 Cartographer 官方文档Cartographer 从入门到精通 1. Cartographer 安装 1.1 前置条件 推荐在刚装好的 Ubuntu 16.04 或 Ubuntu 18.04 上进行编译ROS 安装&#xff1a;ROS学习1&#xff1a;ROS概述与环境搭建 1.2 依赖库安装 资源下载完解压并执行以下指令 https://pa…

Vue项目创建和nodejs使用

Vue项目创建和nodejs使用 一、环境准备1.1.安装 node.js【下载历史版本node-v14.21.3-x64】1.2.安装1.3.检查是否安装成功&#xff1a;1.4.在Node下新建两个文件夹 node_global和node_cache并设置权限1.5.配置npm在安装全局模块时的路径和缓存cache的路径1.6.配置系统变量&…

Linux多线程[二]

引入知识 进程在线程内部执行是OS的系统调度单位。 内核中针对地址空间&#xff0c;有一种特殊的结构&#xff0c;VM_area_struct。这个用来控制虚拟内存中每个malloc等申请的空间&#xff0c;来区别每个malloc的是对应的堆区哪一段。OS可以做到资源的精细度划分。 对于磁盘…

C#调用WechatOCR.exe实现本地OCR文字识别

最近遇到一个需求&#xff1a;有大量的扫描件需要还原为可编辑的文本&#xff0c;很显然需要用到图片OCR识别为文字技术。本来以为这个技术很普遍的&#xff0c;结果用了几个开源库&#xff0c;效果不理想。后来&#xff0c;用了取巧的方法&#xff0c;直接使用了WX的OCR识别模…

算法与数据结构

算法与数据结构 前言 什么是算法和数据结构&#xff1f; 你可能会在一些教材上看到这句话&#xff1a; 程序 算法 数据结构 算法&#xff08;Algorithm&#xff09;&#xff1a;是指解题方案的准确而完整的描述&#xff0c;是一系列解决问题的清晰指令&#xff0c;算法代…

【Tomcat】:One or more listeners failed to start.报错解决方案

报错信息:One or more listeners failed to start. Full details will be found in the appropriate container log file. 具体就是web.xml此配置报错: 服务器启动错误Tomcat:One or more listeners failed to start.报错解决方案 IDEA:在使用IDEA运行SSM项目的时候 , Tomcat运…

ChatGpt报错:We ran into an issue while authenticating you解决办法

在登录ChatGpt时报错&#xff1a;Oops&#xff01;,We ran into an issue while authenticating you.(我们在验证您时遇到问题)&#xff0c;记录一下解决过程。 完整报错&#xff1a; We ran into an issue while authenticating you. If this issue persists, please contact…

怎么使用ChatGPT提高工作效率?

怎么使用ChatGPT提高工作效率&#xff0c;这是一个有趣的话题。 相信不同的人有不同的观点&#xff0c;大家的知识背景和从事的工作都不完全相同&#xff0c;所以最终ChatGPT能起到的作用也不一样。 在编程过程中&#xff0c;如果我们要找一个库&#xff0c;我们最先做的肯定…

[缓存] - 2.分布式缓存重磅中间件 Redis

1. 高性能 尽量使用短key 不要存过大的数据 避免使用keys *&#xff1a;使用SCAN,来代替 在存到Redis之前压缩数据 设置 key 有效期 选择回收策略(maxmemory-policy) 减少不必要的连接 限制redis的内存大小&#xff08;防止swap&#xff0c;OOM&#xff09; slowLog …

C语言第二十三弹---指针(七)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、sizeof和strlen的对比 1.1、sizeof 1.2、strlen 1.3、sizeof 和 strlen的对比 2、数组和指针笔试题解析 2.1、⼀维数组 2.2、二维数组 总结 1、si…

每日五道java面试题之java基础篇(八)

第一题.CopyOnWriteArrayList的底层原理是怎样的 ⾸先CopyOnWriteArrayList内部也是⽤过数组来实现的&#xff0c;在向CopyOnWriteArrayList添加元素时&#xff0c;会复制⼀个新的数组&#xff0c;写操作在新数组上进⾏&#xff0c;读操作在原数组上进⾏并且&#xff0c;写操作…

OpenGL-ES 学习(1)---- AlphaBlend

AlphaBlend OpenGL-ES 混合本质上是将 2 个片元的颜色进行调和(一般是求和操作)&#xff0c;产生一个新的颜色 OpenGL ES 混合发生在片元通过各项测试之后&#xff0c;准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值&#xff0c;不再是新&#xf…

Prometheus服务器、Prometheus被监控端、Grafana、监控MySQL数据库、自动发现概述、配置自动发现、Alertmanager

目录 Prometheus概述 部署Prometheus服务器 环境说明&#xff1a; 配置时间 安装Prometheus服务器 添加被监控端 部署通用的监控exporter Grafana 概述 部署Grafana 展示node1的监控信息 监控MySQL数据库 配置MySQL 配置mysql exporter 配置mysql exporter 配置…

算法沉淀——字符串(leetcode真题剖析)

算法沉淀——字符串 01.最长公共前缀02.最长回文子串03.二进制求和04.字符串相乘 01.最长公共前缀 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-prefix/ 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串…

VS Code之Java代码重构和源代码操作

文章目录 支持的代码操作列表调用重构分配变量字段和局部变量的差别Assign statement to new local variable在有参构造函数中将参数指定成一个新的字段 将匿名类转换为嵌套类什么是匿名类&#xff1f;匿名类转换为嵌套类的完整演示 转换为Lambda表达式Lambda 表达式是什么?转…

【51单片机】串口(江科大)

8.1串口通信 1.串口介绍 2.硬件电路 3.电平标准 电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种: 电平标准是数据1和数据O的表达方式,是传输线缆中人为规定的电 压与数据的对应关系,串口常用的电平标准有如下…

C++类和对象-C++运算符重载->加号运算符重载、左移运算符重载、递增运算符重载、赋值运算符重载、关系运算符重载、函数调用运算符重载

#include<iostream> using namespace std; //加号运算符重载 class Person { public: Person() {}; Person(int a, int b) { this->m_A a; this->m_B b; } //1.成员函数实现 号运算符重载 Person operator(const Per…

Redis 单线程

文章目录 Redis单线程架构Redis 单线程访问速度IO多路复用原理 Redis单线程架构 Redis的单线程架构的效果为&#xff1a;Redis的单线程是对于服务端而言的&#xff0c;Redis允许多个Redis用户端同时在线操作&#xff0c;但同时只有一个用户端在和服务端交互。多个用户同时发送…

VueCLI核心知识综合案例TodoList

目录 1 拿到一个功能模块首先需要拆分组件&#xff1a; 2 使用组件实现静态页面的效果 3 分析数据保存在哪个组件 4 实现添加数据 5 实现复选框勾选 6 实现数据的删除 7 实现底部组件中数据的统计 8 实现勾选全部的小复选框来实现大复选框的勾选 9 实现勾选大复选框来…