题解:小U快乐生活事件快乐值最大化
问题描述
小U喜欢分享她的日常生活。她有n个事件可以选择分享,分享第ii个事件需要花费ti的时间和hi的精力来编辑文章,并能够获得ai的快乐值。小U想知道,在总花费时间不超过T且总花费精力不超过H的前提下,她最多可以获得多少快乐值。
解题思路
-
理解问题:我们需要在给定的总时间和总精力的限制下,选择一些事件来最大化快乐值。
-
数据结构选择:我们可以使用动态规划来解决这个问题。定义一个二维数组
dp[i][j],表示在总时间为i和总精力为j的情况下,可以获得的最大快乐值。 -
算法步骤:
- 初始化一个二维数组
dp,大小为(T+1) x (H+1),所有元素初始化为0。 - 遍历每个事件,对于每个事件,更新
dp数组。 - 对于每个事件
(t_i, h_i, a_i),从后向前遍历dp数组,更新dp[i][j]为max(dp[i][j], dp[i-t_i][j-h_i] + a_i),前提是i >= t_i且j >= h_i。
- 初始化一个二维数组
-
返回结果:最终答案就是
dp[T][H]。
def solution(n: int, T: int, H: int, t: list, h: list, a: list) -> int:
# 初始化dp数组,大小为(T+1) x (H+1),所有元素初始化为0
dp = [[0] * (H + 1) for _ in range(T + 1)]
# 遍历每个事件
for i in range(n):
# 从后向前遍历dp数组,更新dp[i][j]
for time in range(T, t[i] - 1, -1):
for energy in range(H, h[i] - 1, -1):
# 更新dp[time][energy]
dp[time][energy] = max(dp[time][energy], dp[time - t[i]][energy - h[i]] + a[i])
# 返回最终结果
return dp[T][H]
if __name__ == '__main__':
print(solution(n = 2, T = 2, H = 2, t = [1, 3], h = [3, 1], a = [3, 4]) == 0)
print(solution(n = 3, T = 5, H = 5, t = [2, 1, 3], h = [1, 3, 2], a = [10, 7, 8]) == 18)
print(solution(n = 1, T = 3, H = 3, t = [4], h = [4], a = [5]) == 0)
学习总结
动态规划通过将复杂问题分解为子问题,并存储子问题的解来避免重复计算,从而提高效率。它适用于各种最优化、计数、存在性、序列、背包和矩阵路径等问题。理解动态规划的关键在于定义状态、找到状态转移方程、初始化状态数组、确定计算顺序和返回结果。
动态规划适用的题目类型
-
最优化问题:
- 例如,最大值、最小值、最长路径等问题。
- 本题就是一个典型的最优化问题,需要在给定的时间和精力限制下,最大化快乐值。
-
计数问题:
- 例如,计算有多少种方式可以到达某个状态。
- 例如,计算有多少种方法可以组成某个金额的硬币组合。
-
存在性问题:
- 例如,判断是否存在某种状态或路径。
- 例如,判断是否可以通过某种操作将一个状态转换为另一个状态。
-
序列问题:
- 例如,最长递增子序列、最长公共子序列等问题。
- 这类问题通常涉及序列的子问题分解。
-
背包问题:
- 例如,0/1背包问题、完全背包问题、多重背包问题等。
- 这类问题通常涉及在给定容量限制下,选择物品以最大化或最小化某个值。
-
矩阵路径问题:
- 例如,计算从矩阵的左上角到右下角的最短路径。
- 这类问题通常涉及矩阵中的路径选择。