草庐IT

Python | 蓝桥杯进阶第三卷——动态规划

四口鲸鱼爱吃盐 2023-04-02 原文

欢迎交流学习~~


专栏: 蓝桥杯Python组刷题日寄


蓝桥杯进阶系列:

🏆 Python | 蓝桥杯进阶第一卷——字符串
🔎 Python | 蓝桥杯进阶第二卷——贪心
💝 Python | 蓝桥杯进阶第三卷——动态规划
✈️ Python | 蓝桥杯进阶第四卷——图论
🌞 Python | 蓝桥杯进阶第五卷——数论
💎 Python | 蓝桥杯进阶第六卷——搜索

Python|蓝桥杯进阶第三卷——动态规划


🎁 能量项链

题目:
时间限制:
1s

内存限制:
128MB

题目描述:
在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有 N 颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为 m,尾标记为 r,后一颗能量珠的头标记为 r,尾标记为 n,则聚合后释放的能量为 m*r*n(Mars单位),新产生的珠子的头标记为 m, 尾标记为 n
需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。
例如:设 N=44 颗珠子的头标记与尾标记依次为 (2,3) (3,5) (5,10) (10,2)。我们用记号 表示两颗珠子的聚合操作,(j◎k) 表示第 j,k两颗珠子聚合后所释放的能量。则第 4、1 两颗珠子聚合后释放的能量为:
(4◎1)=10*2*3=60
这一串项链可以得到最优值的一个聚合顺序所释放的总能量为
((4◎1)◎2)◎3)=10*2*3+10*3*5+10*5*10=710

输入描述:
第一行是一个正整数 N(4≤N≤100),表示项链上珠子的个数。
第二行是 N 个用空格隔开的正整数,所有的数均不超过 1000。第 i 个数为第 i 颗珠子的头标记(1≤i≤N),当 i<N 时,第 i 颗珠子的尾标记应该等于第 i+1 颗珠子的头标记。第 N 颗珠子的尾标记应该等于第 1 颗珠子的头标记。
至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出描述:
只有一行,是一个正整数 E(E ≤ 2.1*10^9),为一个最优聚合顺序所释放的总能量

样例输入:

4
2 3 5 10

样例输出:
710


解题思路

针对动态规划类的题目,我们通常采取以下思路:

  • 确定 dp 数组以及下标的含义
  • 确定递推公式
  • 初始化 dp 数组
  • 确定遍历顺序

接下来的题目我们都会按照这个思路。

确定 dp 数组及其下标的含义:
dp[i][j] 表示第 i 颗珠子到第 j 颗珠子聚合成一颗珠子后所释放的最大能量。

确定递推公式:
dp[i][j] = max(dp[i][k] + dp[k+1][j] + nums[i]*nums[k+1]*nums[j+1]), i ≤ k < j i\leq k <j ik<j, k k k 为断点

这里的 nums[i] 表示第 i 颗珠子的头标记,但注意,项链为环状,我们可以将链状结构复制一份到后方,同时在末尾再加上第1颗珠子的头标记,比如:样例中的 2, 3, 5, 10,经过处理后是 nums=[2, 3, 5, 10, 2, 3, 5, 10, 2].


注意:从第 k 个位置断开(i ~ k 已经聚合成了一个珠子且 k+1 ~ j 也已经聚合成了一个珠子,这个在状态转移的过程中已经处理好了)左右两个珠子聚合得到的能量为 nums[i]*nums[k+1]*nums[j+1]

初始化 dp 数组:
都初始化为0即可。

确定遍历顺序:
顺序遍历即可。


参考代码

n = int(input())
nums = list(map(int, input().split())) * 2
nums.append(nums[0])
dp = [[0 for j in range(2*n)] for i in range(2*n)]
res = 0

# 递推
# 枚举区间长度
for length in range(1, n):
    # 枚举区间起点
    for i in range(2*n):
        # 计算区间终点
        j = i + length
        # 区间终点超出索引,退出
        if j >= 2*n:
            break
        # 枚举区间断点
        for k in range(i, j):
            # 状态转移
            dp[i][j] = max(dp[i][j], dp[i][k]+dp[k+1][j]+nums[i]*nums[k+1]*nums[j+1])
        # 计算res,最大值
        res = max(res, dp[i][j])

print(res)

🌲 夺宝奇兵

题目:
时间限制:
1s

内存限制:
128MB

题目描述:
在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图:

7
3  8
8  1  0
2  7  4  4
4  5  2  6  5

”夺宝奇兵”从山下出发,到达山顶,如何选路才能得到最多的珠宝呢?(每次只能直上或左上)
在上图所示例子中,按照 5-> 7-> 8-> 3-> 7 的顺序,将得到最大值 30.

输入描述:
第一行正整数 N(100 >= N >1),表示山的高度
接下来有 N 行非负整数,第 i 行有 i 个整数 (1 <= i <=N),表示山的第 i 层上从左到右每条路上的珠宝数目。

输出描述:
一个整数,表示从山底到山顶的所能得到的珠宝的最大数目.

样例输入:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

样例输出:
30


解题思路

确定 dp 数组及其下标的含义:
dp[i][j] 表示位置 i,j 对应的珠宝最大数目。

确定递推公式:
dp[i][j] = max(dp[i-1][j] + cell[i][j], dp[i-1][j-1] + cell[i][j])

初始化 dp 数组:
都初始化为0即可。

确定遍历顺序:
从上往下遍历即可。

参考代码

n = int(input())
# cell 为每个位置的珠宝数目
cell = []
for i in range(n):
    cell.append(list(map(int, input().split())))
# dp[i][j] 表示位置 i,j 对应的珠宝最大数目
dp = [[0 for j in range(n)] for i in range(n)]
dp[0][0] = cell[0][0]
# 从上往下遍历
for i in range(n):
    for j in range(i+1):
        dp[i][j] = max(dp[i-1][j] + cell[i][j], dp[i-1][j-1] + cell[i][j])

# 最后一层的最大值
res = max(dp[-1])
print(res)

🚀 和最大子序列

题目:
时间限制:
1s

内存限制:
128MB

题目描述:
对于一个给定的长度为 N 的整数序列 A,它的“子序列”的定义是:A 中非空的一段连续的元素(整数)。你要完成的任务是,在所有可能的子序列中,找到一个子序列,该子序列中所有元素的和是最大的(跟其他所有子序列相比)。程序要求你输出这个最大值。

输入描述:
输入文件的第一行包含一个整数 N,第二行包含 N 个整数,表示 A
其中
1 < = N < = 100000
-10000 <= A[i] <= 10000

输出描述:
输出仅包含一个整数,表示你算出的答案。

样例输入:

5
3 -2 3 -5 4

样例输出:
4


解题思路

确定 dp 数组及其下标的含义:
dp[i] 表示序列 nums[:i+1] 的子序列的最大和。

确定递推公式:
dp[i] = max(dp[i-1]+nums[i], nums[i])

初始化 dp 数组:
初始化为 nums[0] 即可。

确定遍历顺序:
顺序遍历即可。

参考代码

n = int(input())
nums = list(map(int, input().split()))
print(nums[:1])
# dp[i] 表示序列 nums[:i+1] 的子序列的最大和
dp = [nums[0] for i in range(n)]
for i in range(1, len(nums)):
    dp[i] = max(dp[i-1]+nums[i], nums[i])
print(max(dp))

💡 超级玛丽

题目:
时间限制:
1s

内存限制:
128MB

题目描述:
大家都知道" 超级玛丽" 是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳一步或两步。有一次,他要经过一条长为 n 的羊肠小道,小道中有 m 个陷阱,这些陷阱都位于整数位置,分别是 a 1 , a 2 , . . . . , a m a1,a2,...., am a1,a2,....,am,陷入其中则必死无疑。显然,如果有两个挨着的陷阱,则玛丽是无论如何也跳过不去的。
现在给出小道的长度 n,陷阱的个数及位置。求出玛丽从位置 1 开始,有多少种跳跃方法能到达胜利的彼岸(到达位置 n)。

输入描述:
第一行为两个整数 n,m
第二行为 m 个整数,表示陷阱的位置

数据规模和约定
40 >= n >= 3, m >= 1
n > m;
陷阱不会位于 1n

输出描述:
一个整数。表示玛丽跳到 n 的方案数

样例输入:

4 1
2

样例输出:
1


解题思路

确定 dp 数组及其下标的含义:
dp[i] 表示到达位置 i 的跳跃方法数。

确定递推公式:
当满足:index.count(i) == 0 即此处没有陷阱, dp[i] = dp[i-j] + dp[i]

初始化 dp 数组:
初始化为 0 即可。

确定遍历顺序:
顺序遍历即可。


参考代码

n, m = map(int, input().split())
index = list(map(int, input().split()))
# dp[i] 表示到达位置 i 的跳跃方法数
# dp[0] = 0 便于后续处理
dp = [0 for i in range(n+1)]
dp[1] = 1
for i in range(2, n+1):
    for j in [1, 2]:
        # 判断前两个位置是否有陷阱
        if index.count(i) == 0:
            dp[i] = dp[i-j] + dp[i]
print(dp[-1])

🍞 2^k进制数

题目:
时间限制:
1s

内存限制:
128MB

题目描述:
r r r 是个 2 k 2^k 2k 进制数,并满足以下条件:

  • r r r 至少是个 2 2 2 位的 2 k 2^k 2k 进制数。
  • 作为 2 k 2^k 2k 进制数,除最后一位外, r r r 的每一位严格小于它右边相邻的那一位。
  • r r r 转换为 2 2 2 进制数 q q q 后,则 q q q 的总位数不超过 w w w

在这里,正整数 k ( 1 ≤ k ≤ 9 ) k(1≤k≤9) k(1k9) w ( k < w ≤ 30000 ) w(k<w≤30000) w(k<w30000) 是事先给定的。

问:满足上述条件的不同的 r r r 共有多少个?
我们再从另一角度作些解释:设 S S S 是长度为 w w w 的 01字符串(即字符串 S S S w w w01组成), S S S 对应于上述条件中的 q q q。将 S S S 从右起划分为若干个长度为 k k k 的段,每段对应一位 2 k 2^k 2k 进制的数,如果 S S S 至少可分成 2 2 2 段,则 S S S 所对应的二进制数又可以转换为上述的 2 k 2^k 2k 进制数 r r r

例:设 k = 3 , w = 7 k=3,w=7 k=3w=7。则 r r r 是个八进制数 ( 2 3 = 8 ) (2^3=8) (23=8)。由于 w = 7 w=7 w=7,长度为 7 的 01 字符串按 3位一段分,可分为 3 段(即1,3,3,左边第一段只有一个二进制位),则满足条件的八进制数有:

2位数:
高位为16 个(即 12,13,14,15,16,17 ),高位为 25 个,…,高位为61个(即67 )。共 6+5+…+1=21 个。

3位数:
高位只能是1,第 2 位为 25 个(即123,124,125,126,127),第2位为34个,…,第 2 位为 61个(即 167)。共5+4+…+1=15个。
所以,满足要求的 r r r 共有 36个。

输入描述:
只有1行,为两个正整数,用一个空格隔开:
k k k w w w

输出描述:
1行,是一个正整数,为所求的计算结果,即满足条件的不同的 r r r 的个数(用十进制数表示),要求最高位不得为0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。
(提示:作为结果的正整数可能很大,但不会超过200位)

样例输入:
3 7
样例输出:
36


解题思路

确定 dp 数组及其下标的含义:
dp[i][j] 表示有 (i+1) 位数字,最高位数字是 j 时满足条件的数字个数。

确定递推公式:
j!=0dp[i][j] = dp[i-1][j+1]+dp[i-1][j+2]+dp[i-1][j+3]······
也就是说最高位不是0的时候,满足条件的数字个数是,第二高位的数字大于最高位的数字的情况的和。
j==0dp[i][j] = dp[i-1][j]+dp[i-1][j+1]+dp[i-1][j+2]+dp[i-1][j+3]······
如果最高位是 0,那么第二高位数字则可以取0。也就比上一个情况多加了个 dp[i-1][j]

初始化 dp 数组:
dp[0][j]=1 即只有一位数字时只有一种情况

确定遍历顺序:
顺序遍历即可。

此外注意最终结果的计算和处理,具体见代码。


参考代码

import math
k, w = map(int, input().split())
# rows, cols 为dp数组的行数和列数
rows, cols = w//k+1, 2**k
# i 是 2^k 进制下数字的位数
# j 是 每一位上可以取到的值
# dp[i][j] 表示有 (i+1) 位数字,最高位数字是 j 时满足条件的数字个数
dp = [[0 for j in range(cols)] for i in range(rows)]
# 初始化 res,为结果
res = 0

# dp 数组初始化
# dp[0][j] 表示有 1 位数字的情况
for j in range(cols):
    dp[0][j] = 1

# 递推
for i in range(1, rows):
    for j in range(cols):
        dp[i][j] = sum(dp[i-1][j+1:])
        if j == 0:
            dp[i][j] += dp[i-1][j]

# 计算最后的结果
if w%k == 0:
    # 此时最高位可以取 0 到 cols, 即最后一行所有情况都可以用
    res = sum(dp[-1])
else:
    # 此时最高位只能取 0 到 2**(w%k)-1
    res = sum(dp[-1][:2**(w%k)])

# 题目中要求位数 >= 2
# 需要减去只有一位数的情况
if w/k <= 1:
    res = 0
else:
    res -= 2**k
print(res)

有关Python | 蓝桥杯进阶第三卷——动态规划的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  3. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  4. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  5. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  6. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  7. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  8. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  9. python - 是否可以使用 Ruby 或 Python 禁用 anchor /引用来发出有效的 YAML? - 2

    是否可以在PyYAML或Ruby的Psych引擎中禁用创建anchor和引用(并有效地显式列出冗余数据)?也许我在网上搜索时遗漏了一些东西,但在Psych中似乎没有太多可用的选项,而且我也无法确定PyYAML是否允许这样做.基本原理是我必须序列化一些数据并将其以可读的形式传递给一个不是真正的技术同事进行手动验证。有些数据是多余的,但我需要以最明确的方式列出它们以提高可读性(anchor和引用是提高效率的好概念,但不是人类可读性)。Ruby和Python是我选择的工具,但如果有其他一些相当简单的方法来“展开”YAML文档,它可能就可以了。 最佳答案

  10. .net - .NET 将如何影响 Python 和 Ruby 应用程序? - 2

    我很好奇.NET将如何影响Python和Ruby应用程序。用IronPython/IronRuby编写的应用程序是否会非常特定于.NET环境,以至于它们实际上将变得特定于平台?如果他们不使用任何.NET功能,那么IronPython/IronRuby相对于非.NET同类产品的优势是什么? 最佳答案 我不能说任何关于IronRuby的东西,但是大多数Python实现(如IronPython、Jython和PyPy)都试图尽可能忠实于CPython实现。不过,IronPython正在迅速成为这方面的佼佼者之一,并且在PlanetPyth

随机推荐