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

news2024/11/26 12:23:09

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

def fun(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    dp = [0] * (n + 1)
    dp[0] = 0
    dp[1] = 1

    for 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] = 1

dp[0] = 1
dp[1] = 1 - vis[1]

for i in range(2,N + 1):
    if vis[i] == 1:
        continue
    dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007

print(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 + dy
            if 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 0
    r,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 + dy
            if 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 = 0
    for i in range(r):
        for j in range(c):
            result = max(result,dfs(i,j))
    return result


a = [
  [9, 9, 4],
  [6, 6, 8],
  [2, 1, 1]
]
print(longestpath(a))

运行结果:

 

答案是正确的。

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

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

 

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

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

相关文章

机器学习3----决策树

这是前期准备 import numpy as np import pandas as pd import matplotlib.pyplot as plt #ID3算法 #每个特征的信息熵 # target : 账号是否真实&#xff0c;共2种情况 # yes 7个 p0.7 # no 3个 p0.3 info_D-(0.7*np.log2(0.7)0.3*np.log2(0.3)) info_D #日志密度…

一周学会Django5 Python Web开发-Django5 Hello World编写

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计14条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Cocos2dx-lua ScrollView[一]基础篇

一.ScrollView概述 cocos游戏中ScrollView控件大量使用,95%以上的项目都会使用ScrollView,个别游戏可能全部使用翻页的滑动效果。如果想要精通Cocos的UI开发,精通ScrollView控件非常关键,因此对ScrollView的使用进行总结很有必要。 下文缩写说明:sv = ScrollView, item代…

Python Matplotlib 的学习笔记

Python Matplotlib 的学习笔记 0. Python Matplotlib 简介1. 为什么要用 Matplotlib&#xff1f;2. Matplotlib 基础类详解2-1. Line&#xff08;线&#xff09;2-2. Marker&#xff08;标记&#xff09;2-3. Text&#xff08;文本&#xff09;2-4. Legend&#xff08;图例&…

数据结构实验三 图的深度优先搜索(包含求连通分量)

全屏浏览作者 王群芳 单位 合肥师范学院 以邻接矩阵作存储结构&#xff0c;编写程序对给定的无向图&#xff08;图中包含n个顶点&#xff0c;编号为0至n-1&#xff09;进行深度优先遍历&#xff0c;并在遍历的过程中计算图G的连通分量个数及边的数目。 本题限定在遍历过程中…

车载软件架构 —— Adaptive AUTOSAR软件架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师&#xff08;Wechat&#xff1a;gongkenan2013&#xff09;。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 本就是小人物&#xff0c;输了就是输了&#…

蓝桥杯:C++排序

排序 排序和排列是算法题目常见的基本算法。几乎每次蓝桥杯软件类大赛都有题目会用到排序或排列。常见的排序算法如下。 第(3)种排序算法不是基于比较的&#xff0c;而是对数值按位划分&#xff0c;按照以空间换取时间的思路来排序。看起来它们的复杂度更好&#xff0c;但实际…

数模.传染病模型plus

一、SIS模型 二、SIR模型 三、SIRS模型 四、SEIR模型

Python第十六章(面向对象)

类&#xff1a;是对一系列相同特征和行为的事物的统称&#xff0c;是一个抽象的概念&#xff0c;不是真实存在的事物 特征&#xff1a;属性/变量 行为&#xff1a;方法/函数 对象&#xff1a;类创建出来的真实事物 类和对象的关系&#xff1a;先构造一个类&#xff0…

GitHub项目推荐-InstantID

项目地址 https://github.com/InstantID/InstantID 项目简述 InstantID是一个图生图项目&#xff0c;仅仅通过一张正脸的图片&#xff0c;就能生成各种风格的人像。该项目的文档描述比较齐备&#xff0c;所以复现起来成本比较小。 项目截图 这是项目介绍中的一张截图&…

二叉树基础总结

目录 树的定义&#xff1a; 深度和高度&#xff1a; 二叉树 由来 二叉树种类&#xff1a; 满二叉树&#xff1a; 完全二叉树&#xff1a; 严格二叉树&#xff08;Strict Binary Tree&#xff09;&#xff1a; 平衡二叉树&#xff08;Balanced Binary Tree&#xff09;&…

【阅读笔记】空域保边降噪《Side Window Filtering》

1、保边滤波背景 保边滤波器的代表包括双边滤波、引导滤波&#xff0c;但是这类滤波器有一个问题&#xff0c;它们均将待处理的像素点放在了方形滤波窗口的中心。但如果待处理的像素位于图像纹理或者边缘&#xff0c;方形滤波核卷积的处理结果会导致这个边缘变模糊。 基于这个…

算法刷题:有效三角形个数

有效三角形个数 .题目链接题目详情算法原理补充知识点双指针:对撞指针 我的答案 . 题目链接 有效三角形个数 题目详情 算法原理 补充知识点 有效三角形需要满足的条件: ab>cac>bbc>a 其实在满足1的时候,c是最大的,那么2和3是显然成立的,因此我们可以这样解题: 对…

【北邮鲁鹏老师计算机视觉课程笔记】10 Classification 分类

【北邮鲁鹏老师计算机视觉课程笔记】10 Classification 分类 1 图像识别的基本范式 检测问题&#xff1a;不仅要知道有没有&#xff0c;还要知道在哪里 分类是整图级标签&#xff0c;检测是区域级标签&#xff0c;分割是像素级标签 2 检测任务的应用 3 单实例识别与类别识别…

九、OpenCV自带colormap

项目功能实现&#xff1a;每隔1500ms轮流自动播放不同风格图像显示&#xff0c;按下Esc键退出 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 colormap.h #pragma once #include<opencv2/opencv.hpp> using namespace cv;class ColorMap { public:vo…

Rust 数据结构与算法:1算法分析之乱序字符串检查

Rust 数据结构与算法 一、算法分析 算法是通用的旨在解决某种问题的指令列表。 算法分析是基于算法使用的资源量来进行比较的。之所以说一个算法比另一个算法好,原因就在于前者在使用资源方面更有效率,或者说前者使用了更少的资源。 ●算法使用的空间指的是内存消耗。算法…

浅谈业务场景中缓存的使用

业务场景中缓存的使用 一、背景二、缓存分类1.本地缓存2.分布式缓存 三、缓存读写模式1.读请求2.写请求 四、缓存穿透1.缓存空对象2.请求校验3.请求来源限制4.布隆过滤器 五、缓存击穿1.改变过期时间2.串行访问数据库 六、缓存雪崩1.避免集中过期2.提前更新缓存 七、缓存与数据…

初始JAVA

目录 一、输出HelloWorld 1.1开发步骤 1.2 编写 1.3 编译 1.4 运行 二、 HelloWorld小结 2.1 Java程序的结构与格式 2.2 Java程序的入口 2.3 两种常见的输出语句 2.4 源文件名与类名 三、 注释(comment) 四、 Java API文档 五、 Java核心机制&#xff1a;JVM 5.1…

OpenAI宣布ChatGPT新增记忆功能;谷歌AI助理Gemini应用登陆多地区

&#x1f989; AI新闻 &#x1f680; OpenAI宣布ChatGPT新增记忆功能&#xff0c;可以自由控制内存&#xff0c;提供个性化聊天和长期追踪服务 摘要&#xff1a;ChatGPT新增的记忆功能可以帮助AI模型记住用户的提问内容&#xff0c;并且可以自由控制其内存。这意味着用户不必…

第三百二十二回

文章目录 1. 概念介绍2. 使用方法2.1 基本用法2.2 缓冲原理 3. 示例代码4. 内容总结 我们在上一章回中介绍了"FadeInImage组件"相关的内容&#xff0c;本章回中将介绍CachedNetworkImage组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…