2024蓝桥杯每日一题(线性DP)

本文介绍了备战2024年蓝桥杯的四道Python题目,包括乌龟棋的分数最大化、最长上升子序列、最长公共子序列以及松散子序列的求解,均采用动态规划方法进行求解并提供了Python代码示例。
摘要由CSDN通过智能技术生成

备战2024年蓝桥杯 -- 每日一题
Python大学A组

        试题一:乌龟棋
        试题二:最长上升子序列
        试题三:最长公共子序列
        试题四:松散子序列


试题一:乌龟棋

【题目描述】

        小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。乌龟棋的棋盘只有一行,该行有 N 个格子,每个格子上一个分数(非负整数)。棋盘第 1 格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。乌龟棋中共有 M 张爬行卡片,分成 4 种不同的类型(M 张卡片中不一定包含所有 4 种类型的卡片),每种类型的卡片上分别标有 1、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。 游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。 游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

【输入格式】

        输入文件的每行中两个数之间用一个空格隔开。

        第 1 行 2 个正整数 N 和 M,分别表示棋盘格子数和爬行卡片数。

        第 2 行 N 个非负整数,a1,a2,……,aN,其中 ai 表示棋盘第 i 个格子上的分数。

        第 3 行 M 个整数,b1,b2,……,bM表示 M 张爬行卡片上的数字。

        输入数据保证到达终点时刚好用光 M 张爬行卡片。

【输出格式】

        输出只有 1 行,包含 1 个整数,表示小明最多能得到的分数。

【数据范围】

        1≤N≤350,
        1≤M≤120,
        0≤ai≤100,
        1≤bi≤4,
        每种爬行卡片的张数不会超过 4040。

【输入样例】

9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1

【输出样例】

73

【解题思路】

        线性DP,四种卡片,所以枚举四维,状态转移方程应该为f[a][b][c][d] = max(f[a][b][c][d] ,f[a-1][b][c][d]+a[t]),对应的t为跳的总长度,其他维度同理。

【Python程序代码】

n,m = map(int,input().split())
ma = list(map(int,input().split()))
mb = list(map(int,input().split()))
cnt = [0]*5
for i in mb:
    cnt[i]+=1
f = [[[[0]*(cnt[4]+1) for _ in range(cnt[3]+1)] for i in range(cnt[2]+1)]for j in range(cnt[1]+1)]
for a in range(cnt[1]+1):
    for b in range(cnt[2]+1):
        for c in range(cnt[3]+1):
            for d in range(cnt[4]+1):
                t = a*1+b*2+c*3+d*4
                if a:f[a][b][c][d]= max(f[a][b][c][d],f[a-1][b][c][d]+ma[t])
                if b:f[a][b][c][d]= max(f[a][b][c][d],f[a][b-1][c][d]+ma[t])
                if c:f[a][b][c][d]= max(f[a][b][c][d],f[a][b][c-1][d]+ma[t])
                if d:f[a][b][c][d]= max(f[a][b][c][d],f[a][b][c][d-1]+ma[t])
print(f[cnt[1]][cnt[2]][cnt[3]][cnt[4]]+ma[0])

试题二:最长上升子序列

【题目描述】

        给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。

【输入格式】

        第一行包含整数 N。

        第二行包含 N 个整数,表示完整序列。

【输出格式】

        输出一个整数,表示最大长度。

【数据范围】

        1≤N≤1000,
        −109≤数列中的数≤109

【输入样例】

7
3 1 2 1 8 5 6

【输出样例】

4

【解题思路】

        状态转移方程为f[i] = max(f[i],f[j]+1)

【Python程序代码】

n = int(input())
a = [0] + list(map(int, input().split()))
f = [1]*(n+5)
res = 1
for i in range(2,n+1):
    for j in range(1,i):
        if a[i]>a[j]:f[i]=max(f[i],f[j]+1)
        res = max(res,f[i])
print(res)

试题三:最长公共子序列

【题目描述】

        给定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。

【输入格式】

        第一行包含两个整数 N 和 M。

        第二行包含一个长度为 N 的字符串,表示字符串 A。

        第三行包含一个长度为 M 的字符串,表示字符串 B。

        字符串均由小写字母构成。

【输出格式】

        输出一个整数,表示最大长度。

【数据范围】

        1≤N,M≤1000

【输入样例】

4 5
acbd
abedc

【输出样例】

3

【解题思路】

        线性DP, 当a[i]==b[j]是f[i][j] = f[i-1][j-1]+1,否则f[i][j] = max(f[i-1][j],f[i][j-1])

【Python程序代码】

n,m = map(int,input().split())
a =" " + input()
b =" " + input()
f = [[0]*(max(n,m)+1) for _ in range(max(n,m)+1)]
for i in range(1,n+1):
    for j in range(1,m+1):
        if a[i]==b[j]:
            f[i][j] = f[i-1][j-1]+1
        else:
            f[i][j] = max(f[i-1][j],f[i][j-1])
print(f[n][m])

试题四:松散子序列

【题目描述】

        给定一个仅含小写字母的字符串 s,假设 s 的一个子序列 t 的第 i 个字符对应了原字符串中的第 pi 个字符。

        我们定义 s 的一个松散子序列为:对于 i>1 总是有 pi−pi−1≥2。设一个子序列的价值为其包含的每个字符的价值之和(a∼z分别为 1∼26)。求 s 的松散子序列中的最大价值。

【输入格式】

        输入一行包含一个字符串 s。

【输出格式】

        输出一行包含一个整数表示答案。

【数据范围】

        对于 20%20% 的评测用例,|s|≤10|;
        对于 40%40% 的评测用例,|s|≤300;
        对于 70%70% 的评测用例,|s|≤5000;
        对于所有评测用例,1≤|s|≤106,字符串中仅包含小写字母。

【输入样例】

azaazaz

【输出样例】

78

【解题思路】

         题意就是不能取连续的字母,所以考虑用状态机,f[i][j]其中j为0时表示不取,为1时表示取,所以f[i][0] = max(f[i-1][1],f[i-1][0]),f[i][1] = f[i-1][0] + s[i] - 'a' +1

【Python程序代码】

s =" " + input()
f = [[0,0] for _ in range(len(s)+10)]
for i in range(1,len(s)):
    f[i][0] = max(f[i-1][0],f[i-1][1])
    f[i][1] = f[i-1][0] + ord(s[i]) -  ord('a') + 1
print(max(f[len(s)-1][0],f[len(s)-1][1]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学数学的懒哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值