题目解析
题目:小R和小S在探险过程中发现了一个装满金币的宝箱。宝箱里有N枚金币,他们决定按照以下规则来分配:
- 小R和小S轮流选取金币,且小R先选。
- 如果当前剩余的金币数量为偶数时,可以选择拿走一半的金币,或者只拿走一枚金币。
- 如果当前剩余的金币数量为奇数时,只能拿走一枚金币。
两人都会采取最优策略来获取更多的金币。现在,你需要计算小R和小S最终各自拿走的金币数量。
思路:
-
动态规划:我们可以使用动态规划来解决这个问题。定义一个二维数组
dp,其中dp[i][0]表示当小R面对i枚金币时,他能拿到的最大金币数,dp[i][1]表示小S能拿到的最大金币数。 -
状态转移:
- 当金币数为奇数时,小R只能拿走一枚金币,剩下的金币数变为偶数,轮到小S拿。此时,小R能拿的金币数为
dp[i-1][1] + 1,小S则根据dp[i-1][0]来决定自己的最优策略。 - 当金币数为偶数时,小R可以选择拿走一半或者一枚金币。我们需要比较这两种情况下小R能拿到的金币数,选择最大的那个。对于拿走一半的情况,剩下的金币数为
i//2,是偶数,小S会根据dp[i//2][0]来决定自己的最优策略。
- 当金币数为奇数时,小R只能拿走一枚金币,剩下的金币数变为偶数,轮到小S拿。此时,小R能拿的金币数为
-
初始化:
dp[0][0] = 0, dp[0][1] = 0,表示没有金币时,两人都拿不到金币。
图解:
(由于文字表述的限制,无法直接给出图解,但可以通过代码逻辑来理解动态规划的状态转移过程。)
代码详解:
python复制代码
def solution(N: int) -> list:
dp = [[0, 0] for _ in range(N + 1)]
for i in range(1, N + 1):
if i % 2 == 1:
dp[i][0] = dp[i - 1][1] + 1
dp[i][1] = dp[i - 1][0]
else:
take_one = dp[i - 1][1] + 1
take_half = dp[i // 2][1] + i // 2
if take_one > take_half:
dp[i][0] = take_one
dp[i][1] = dp[i - 1][0]
else:
dp[i][0] = take_half
dp[i][1] = dp[i // 2][0]
return [dp[N][0], dp[N][1]]
知识总结
本次刷题让我深刻理解了动态规划在解决策略优化问题中的应用。动态规划通过将问题分解为子问题,并存储子问题的解来避免重复计算,从而提高了算法的效率。对于本题,通过定义dp数组来记录每个状态下的最优解,并根据状态转移方程进行求解,最终得到了小R和小S各自能拿到的最大金币数。
对于入门同学,我建议先从简单的动态规划问题开始练习,逐步掌握动态规划的基本思想和方法。同时,要多看题解和代码实现,理解不同问题的动态规划解法之间的共性和差异。
学习计划
结合豆包MarsCode AI刷题功能,我制定了以下高效学习方法:
- 制定刷题计划:每天安排一定的时间进行刷题,并根据自己的掌握情况逐步增加难度。
- 分类练习:将题目按照知识点进行分类,有针对性地进行练习,以巩固和加深对知识点的理解。
- 利用错题:对于做错的题目,要认真分析错误原因,并重新练习相关知识点,直到完全掌握。
- 定期总结:每周或每月对所学知识点进行总结和梳理,形成自己的知识体系。
工具运用
豆包MarsCode AI刷题功能为我提供了丰富的题目资源和智能的刷题建议。为了更好地利用这一功能,我将其与其他学习资源相结合:
- 结合视频教程:在刷题前,先观看相关的视频教程,了解题目的基本思路和解法。
- 查看题解:对于难以理解的题目,我会查看其他用户的题解和代码实现,以拓宽自己的解题思路。
- 参与讨论:在刷题过程中,积极参与讨论区,与其他用户交流心得和经验,共同进步。
通过以上方法,我相信自己能够在刷题过程中不断提高自己的编程能力和算法水平。