问题描述
小E在一个游戏中遇到了 nn 个按顺序出现的怪物,每个怪物都有其特定的血量 hihi 和攻击力 aiai。小E的初始血量为 HH,攻击力为 AA。 游戏规则如下:
- 小E可以击败一个血量和攻击力都小于她当前属性的怪物。
- 对于第一个击败的怪物,需要满足其血量小于 HH 且攻击力小于 AA。
- 击败怪物后,小E会获得该怪物的属性值。
- 为了保持战斗节奏,要求击败的怪物序列中,后一个怪物的血量和攻击力都必须严格大于前一个怪物。
小E想知道,她最多能击败多少怪物。
测试样例
样例1:
输入:
n = 3, H = 4, A = 5, h = [1, 2, 3], a = [3, 2, 1]
输出:1
样例2:
输入:
n = 5, H = 10, A = 10, h = [6, 9, 12, 4, 7], a = [8, 9, 10, 2, 5]
输出:2
样例3:
输入:
n = 4, H = 20, A = 25, h = [10, 15, 18, 22], a = [12, 18, 20, 26]
输出:3
思路
目标:判断最多能够击杀多少只怪物。
- 初始条件检查:
- 首先,检查是否有怪物满足小E的初始条件(血量小于
H且攻击力小于A)。
- 首先,检查是否有怪物满足小E的初始条件(血量小于
- 动态规划:
- 使用动态规划来记录小E在击败每个怪物后的状态,并尝试找到一个最长的严格递增的怪物序列。
- 状态转移:
- 对于每个怪物,检查是否可以击败它,并且击败它后是否能形成一个更长的严格递增序列。
具体做法
-
初始条件检查:
- 遍历所有怪物,检查每个怪物的血量和攻击力是否都小于小E的初始血量
H和攻击力A。 - 如果满足条件,标记该怪物可以被击败。
# 初始化一个数组来记录每个怪物是否可以被击败 can_defeat = [False] * n # 检查每个怪物是否可以被初始状态的小E击败 for i in range(n): if h[i] < H and a[i] < A: can_defeat[i] = True - 遍历所有怪物,检查每个怪物的血量和攻击力是否都小于小E的初始血量
-
动态规划数组:
- 使用动态规划来记录小E在击败每个怪物后的状态,并尝试找到一个最长的严格递增的怪物序列。
- 动态规划数组
dp[i]表示以第i个怪物结尾的最长严格递增序列的长度。。 - 初始化
dp数组为1,因为每个怪物本身至少可以形成长度为1的序列。
dp = [1] * n -
状态转移:
- 对于每个怪物
i,检查所有之前的怪物j。 - 如果
j可以被击败,且i的属性严格大于j,则更新dp[i]为dp[j] + 1。 - 通过这种方式,逐步构建最长的严格递增序列。
for i in range(n): # 遍历每个怪物 if can_defeat[i]: # 如果当前怪物可以被击败 for j in range(i): # 检查所有之前的怪物 # 如果之前的怪物可以被击败,并且当前怪物的属性(攻击力和血量)严格大于之前的怪物 if can_defeat[j] and h[i] > h[j] and a[i] > a[j]: dp[i] = max(dp[i], dp[j] + 1) # 返回 dp 数组中的最大值 return max(dp) - 对于每个怪物
-
返回结果:
- 返回
dp数组中的最大值,即小E最多能击败的怪物数量。
- 返回
完整代码
def solution(n: int, H: int, A: int, h: list, a: list) -> int:
# 初始化一个数组来记录每个怪物是否可以被击败
can_defeat = [False] * n
# 检查每个怪物是否可以被初始状态的小E击败
for i in range(n):
if h[i] < H and a[i] < A:
can_defeat[i] = True
# 动态规划数组,dp[i] 表示以第 i 个怪物结尾的最长严格递增序列的长度
dp = [1] * n
# 遍历每个怪物
for i in range(n):
# 如果当前怪物可以被击败
if can_defeat[i]:
# 检查所有之前的怪物
for j in range(i):
# 如果之前的怪物可以被击败,并且当前怪物的属性(攻击力和血量)严格大于之前的怪物
if can_defeat[j] and h[i] > h[j] and a[i] > a[j]:
# 更新 dp[i]
dp[i] = max(dp[i], dp[j] + 1)
# 返回 dp 数组中的最大值
return max(dp)
if __name__ == '__main__':
print(solution(3, 4, 5, [1, 2, 3], [3, 2, 1]) == 1)
print(solution(5, 10, 10, [6, 9, 12, 4, 7], [8, 9, 10, 2, 5]) == 2)
print(solution(4, 20, 25, [10, 15, 18, 22], [12, 18, 20, 26]) == 3)
知识点整理
-
动态规划(Dynamic Programming) :
- 动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。
- 在本题中,我们使用动态规划来记录每个怪物被击败后的最长严格递增序列的长度。
-
状态转移方程:
- 状态转移方程是动态规划中的关键部分,它描述了如何从子问题的解推导出原问题的解。
- 在本题中,状态转移方程为
dp[i] = max(dp[i], dp[j] + 1),表示如果怪物i可以被击败且属性严格大于怪物j,则更新dp[i]。
-
数组操作:
- 使用数组来存储和操作数据是编程中的基本技能。
- 在本题中,我们使用数组
can_defeat来记录每个怪物是否可以被击败,使用数组dp来记录最长严格递增序列的长度。
-
循环和条件判断:
- 使用循环和条件判断来遍历和处理数据是编程中的基本操作。
- 在本题中,我们使用嵌套循环来遍历怪物列表,并使用条件判断来检查怪物的属性是否满足要求。
感受
更熟悉动态规划了。