目录
一、P5127 三带一(分类讨论)
小蓝和小桥玩斗地主,小蓝只剩四张牌了,他想知道是否是“三带一”牌型。
所谓“三带一”牌型,即四张手牌中,有三张牌一样,另外一张不与其他牌相同,换种说法,四张手牌经过重新排列后,可以组成 AAAB 型。
1.三带一 - 蓝桥云课https://www.lanqiao.cn/problems/5127/learning/?problem_list_id=27&page=1
蓝桥杯python语言基础(2)——选择结构-CSDN博客https://blog.csdn.net/m0_73631172/article/details/145213659
# 输入
T=int(input())
for i in range(T):
T_list=input()
# 分类讨论
count={}
for i in T_list:
if i in count:
count[i]+=1
else:
count[i]=1
flag=0
for j in count:
if count[j]==3:
flag=1
if flag==1:
print("Yes")
else:
print("No")
# 输入处理
T = int(input())
for _ in range(T):
T_list = input().strip()
count = {} # 初始化统计字典
for i in T_list:
if i in count:
count[i] += 1
else:
count[i] = 1
# 判断是否为“三带一”牌型
if 3 in count.values():
#if 3 in count.values() and 1 in count.values():
print("Yes")
else:
print("No")
from collections import Counter
# 输入处理
T = int(input()) # 读取轮数
for _ in range(T):
cards = input().strip() # 读取每轮的手牌
count = Counter(cards) # 统计每张牌的出现次数
# 判断是否为“三带一”牌型
print("Yes" if sorted(count.values()) == [1, 3] else "No")
对比总结
特性 | 第一段代码 | 第二段代码 | 第三段代码 |
---|---|---|---|
统计方式 | 手动统计 | 手动统计 | 使用 Counter |
判断逻辑 | 仅判断是否存在字符出现3次 | 判断是否存在字符出现3次 | 判断是否同时存在字符出现3次和1次 |
代码简洁性 | 较复杂 | 较复杂 | 简洁 |
适用性 | 仅适用于简单判断 | 仅适用于简单判断 | 适用于准确判断“三带一”牌型 |
二、P5888 摆玩具(贪心、排序)
小蓝是一个热爱收集玩具的小伙子,他拥有 n 个不同的玩具。
这天,他把 n 个玩具按照高度顺序从矮到高摆放在了窗台上,然后,他希望将这些玩具分成 k 个段,使得所有分段的极差之和尽可能小。
3.摆玩具 - 蓝桥云课https://www.lanqiao.cn/problems/5888/learning/?problem_list_id=27&page=1 蓝桥杯python基础算法(2-2)——基础算法(G)——离散化、贪心_蓝桥杯贪心python讲解-CSDN博客
https://blog.csdn.net/m0_73631172/article/details/145399671
# 输入
n,k=map(int,input().split())
n_list=list(map(int,input().split()))
# [贪心]
# 不断选择最大的差值作为分界点
#计算相邻差值
diff=[]
for i in range(1,n):
diff.append(n_list[i]-n_list[i-1])
# [排序]
diff.sort(reverse=True)
# 将相邻最大差值的分段,减去最大的k个,剩下的就是最小极差
for i in range(k-1): #k-1
diff.pop(0)
# 求的是极小差值的和
print(sum(diff))
# 输入
n,k=map(int,input().split())
n_list=list(map(int,input().split()))
# [贪心]
# 计算所有差值的和减去其中k的最大差值的和就是最小差值的和
#计算相邻差值
diff=[]
for i in range(1,n):
diff+=[n_list[i]-n_list[i-1]]
# [排序]
total=n_list[-1]-n_list[0]
diff.sort(reverse=True)
for i in range(k-1):
total-=diff[i]
print(total)
# 输入
n, k = map(int, input().split())
h = list(map(int, input().split()))
# 初始化DP数组
dp_prev = [h[i] - h[0] for i in range(n)]
dp_curr = [float('inf')] * n
# 动态规划求解
for j in range(1, k): # 分段数
for i in range(n): # 元素数
dp_curr[i] = float('inf')
for m in range(j - 1, i): # 分段点
dp_curr[i] = min(dp_curr[i], dp_prev[m] + (h[i] - h[m]))
# 更新dp_prev
dp_prev, dp_curr = dp_curr, dp_prev
print(dp_prev[-1])
特性 | 第一段代码(贪心) | 第二段代码(贪心改进) | 第三段代码(动态规划) |
---|---|---|---|
算法 | 贪心 | 贪心 | 动态规划 |
时间复杂度 | O(nlogn) | O(nlogn) | O(n2⋅k) |
适用性 | 仅适用于特定情况 | 仅适用于特定情况 | 适用于任意情况 |
代码复杂度 | 简单 | 简单 | 复杂 |
三、P5130 健身【算法赛】(动态规划)
小蓝要去健身,他可以在接下来的 1∼n 天中选择一些日子去健身。
他有 m 个健身计划,对于第 i 个健身计划,需要连续的 2^ki 天,如果成功完成,可以获得健身增益 si ,如果中断,得不到任何增益。
同一个健身计划可以多次完成,也能多次获得健身增益,但是同一天不能同时进行两个或两个以上的健身计划。
但是他的日程表中有 q 天有其他安排,不能去健身,问如何安排健身计划,可以使得 n 天的健身增益和最大。
4.健身【算法赛】 - 蓝桥云课https://www.lanqiao.cn/problems/5130/learning/?problem_list_id=27&page=1
# 输入
n, m, q = map(int, input().split())
ti = [0] + list(map(int, input().split())) + [n + 1]
kisi = []
for _ in range(m):
k, s = map(int, input().split())
kisi.append((2**k, s))
# 分段处理:每段连续可用日期的长度
segments = [ti[i] - ti[i - 1] - 1 for i in range(1, len(ti))]
# 动态规划
dp = [[0] * (m + 1) for _ in range(max(segments) + 1)]
for i in range(1, len(dp)):
for j in range(m):
length, s = kisi[j]
if i >= length:
dp[i][j] = max(dp[i - length][-1] + s, dp[i - 1][-1])
else:
dp[i][j] = dp[i - 1][-1]
dp[i][-1] = max(dp[i])
# 计算结果:将所有段的增益相加,得到最终的最大增益
result = 0
for seg in segments:
result += max(dp[seg])
print(result)
- 采用了分段处理的方法,将日期范围分成多个段,每个段之间是不可用日期。
- 使用了一个二维DP数组来处理每个段的最大收益。
# 输入
n,m,q=map(int,input().split())
ti=list(map(int,input().split()))
kisi=[]
for i in range(m):
kisi.append(tuple(map(int,input().split())))
# 动态规划
dp=[0]*(n+1)
for i in range(1,n+1):
if i in ti:
dp[i]=dp[i-1]
else:
dp[i]=dp[i-1]
for k,s in kisi:
length=2**k
if i>=length and all(j not in ti for j in range(i-length+1,i+1)):
dp[i]=max(dp[i],dp[i-length]+s)
print(dp[n])
# 输入
n,m,q=map(int,input().split())
ti=list(map(int,input().split()))
kisi=[]
for i in range(m):
kisi.append(tuple(map(int,input().split())))
# 标记不可用日期
busy=[False]*(n+1)
for i in ti:
busy[i]=True
# 动态规划
dp=[0]*(n+1)
for i in range(1,n+1):
if i in ti:
dp[i]=dp[i-1]
else:
dp[i]=dp[i-1]
for k,s in kisi:
length=2**k
if i>=length and not any(busy[i-length+1:i+1]):
dp[i]=max(dp[i],dp[i-length]+s)
print(dp[n])
n, m, q = map(int, input().split())
ti = list(map(int, input().split()))
kisi = []
for _ in range(m):
k, s = map(int, input().split())
kisi.append((2**k, s)) # 直接存储 2^k
# 标记不可用日期
busy = set(ti) # 使用集合加速查找
# 动态规划
dp = [0] * (n + 1)
for i in range(1, n + 1):
if i in busy: # 如果第 i 天不可用
dp[i] = dp[i - 1]
else:
dp[i] = dp[i - 1] # 不进行任何健身计划
for length, s in kisi:
if i >= length and all(j not in busy for j in range(i - length + 1, i + 1)):
dp[i] = max(dp[i], dp[i - length] + s)
print(dp[n])
如果不分段处理,可以通过直接对整个日期范围进行动态规划来计算最大健身增益。这种方法在不可用日期较少时是可行的,但在不可用日期较多时,效率较低。
改进:
n, m, q = map(int, input().split())
ti = set(map(int, input().split()))
kisi = []
for i in range(m):
k, s = map(int, input().split())
kisi.append((2 ** k, s))
# 动态规划
dp = [0] * (n + 1)
for i in range(1, n + 1):
if i in ti:
dp[i] = dp[i - 1]
else:
dp[i] = dp[i - 1]
for length, s in kisi:
if i >= length and all(j not in ti for j in range(i - length + 1, i + 1)):
dp[i] = max(dp[i], dp[i - length] + s)
print(dp[n])
能通过全部测试用例检测,但是不显示通过率,存在未知问题。