刷题记录 414.小U生活事件快乐值最大化

36 阅读6分钟

414.小U生活事件快乐值最大化

问题描述

小U喜欢分享她的日常生活。她有n个事件可以选择分享,分享第ii个事件需要花费ti的时间和hi的精力来编辑文章,并能够获得ai的快乐值。小U想知道,在总花费时间不超过T且总花费精力不超过H的前提下,她最多可以获得多少快乐值。

测试样例

样例1:

输入:n = 2 ,T = 2 ,H = 2 ,t = [1, 3] ,h = [3, 1] ,a = [3, 4]
输出:0

样例2:

输入:n = 3 ,T = 5 ,H = 5 ,t = [2, 1, 3] ,h = [1, 3, 2] ,a = [10, 7, 8]
输出:18

样例3:

输入:n = 1 ,T = 3 ,H = 3 ,t = [4] ,h = [4] ,a = [5]
输出:0

思路

可以看作是0/1背包问题,要在给定的时间和精力限制下,选择一组事件让总的快乐值最大化。每个事件只能选择一次,选择某个事件会消耗一定的时间和精力,并带来一定的快乐值。使用dp解决问题,义一个三维的 dp 数组来表示在给定的时间和精力限制下,能达到的最大快乐值:

  • dp[i][j][k] 表示在前 i 个事件中,时间限制为 j,精力限制为 k 时,能够获得的最大快乐值。

递推关系

  • 不选择第 i 个事件:dp[i][j][k] = dp[i-1][j][k]
  • 选择第 i 个事件(如果 j >= t[i] 且 k >= h[i]):dp[i][j][k] = max(dp[i][j][k], dp[i-1][j - t[i]][k - h[i]] + a[i])

初始条件

  • dp[0][j][k] = 0,即没有事件时,最大快乐值为 0。

代码实现

def solution(n: int, T: int, H: int, t: list, h: list, a: list) -> int:
    # 初始化三维 DP 数组,大小为 (n+1) x (T+1) x (H+1) 
    dp = [[[0] * (H + 1) for _ in range(T + 1)] for _ in range(n + 1)] 
    # 遍历每个事件 
    for i in range(1, n + 1): 
        time_required = t[i - 1] # 第 i 个事件的时间需求
        energy_required = h[i - 1] # 第 i 个事件的精力需求 
        happiness = a[i - 1] # 第 i 个事件的快乐值 
        # 遍历所有可能的时间和精力组合 
        for j in range(T + 1): 
            for k in range(H + 1): 
            # 不选择第 i 个事件 
            dp[i][j][k] = dp[i - 1][j][k] 
            # 选择第 i 个事件,如果满足时间和精力的限制 
            if j >= time_required and k >= energy_required: 
                dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - time_required][k - energy_required] + happiness) 
                
    # 返回最大快乐值,考虑所有事件和时间精力限制 
    return dp[n][T][H]

问题描述
小U喜欢分享她的日常生活。她有
n
n个事件可以选择分享,分享第
i
i个事件需要花费
t
i
t
i

的时间和
h
i
h
i

的精力来编辑文章,并能够获得
a
i
a
i

的快乐值。小U想知道,在总花费时间不超过
T
T且总花费精力不超过
H
H的前提下,她最多可以获得多少快乐值。

测试样例
样例1:

输入:n = 2 ,T = 2 ,H = 2 ,t = [1, 3] ,h = [3, 1] ,a = [3, 4]
输出:0

样例2:

输入:n = 3 ,T = 5 ,H = 5 ,t = [2, 1, 3] ,h = [1, 3, 2] ,a = [10, 7, 8]
输出:18

样例3:

输入:n = 1 ,T = 3 ,H = 3 ,t = [4] ,h = [4] ,a = [5]
输出:0 py解决

2024/11/30 01:05:16

重试

删除

固定

复制

下载为word文档

播放

这个问题可以看作是一个 0/1 背包问题。我们需要在给定的时间和精力限制下,选择一组事件,使得总的快乐值最大化。每个事件只能选择一次,选择某个事件会消耗一定的时间和精力,并带来一定的快乐值。

问题分析:

  • 输入

    • n:事件的数量。
    • T:可用的总时间。
    • H:可用的总精力。
    • t[i]:第 i 个事件所需的时间。
    • h[i]:第 i 个事件所需的精力。
    • a[i]:第 i 个事件带来的快乐值。
  • 输出

    • 在时间和精力的限制下,能获得的最大快乐值。

思路:

我们可以用动态规划(DP)来解决这个问题。定义一个三维的 dp 数组来表示在给定的时间和精力限制下,能达到的最大快乐值:

  • dp[i][j][k] 表示在前 i 个事件中,时间限制为 j,精力限制为 k 时,能够获得的最大快乐值。

递推关系

  • 不选择第 i 个事件:dp[i][j][k] = dp[i-1][j][k]
  • 选择第 i 个事件(如果 j >= t[i] 且 k >= h[i]):dp[i][j][k] = max(dp[i][j][k], dp[i-1][j - t[i]][k - h[i]] + a[i])

初始条件

  • dp[0][j][k] = 0,即没有事件时,最大快乐值为 0。

Python 代码实现:

def max_happiness(n, T, H, t, h, a):
    # 初始化三维 DP 数组,大小为 (n+1) x (T+1) x (H+1)
    dp = [[[0] * (H + 1) for _ in range(T + 1)] for _ in range(n + 1)]

    # 遍历每个事件
    for i in range(1, n + 1):
        time_required = t[i - 1]  # 第 i 个事件的时间需求
        energy_required = h[i - 1]  # 第 i 个事件的精力需求
        happiness = a[i - 1]  # 第 i 个事件的快乐值

        # 遍历所有可能的时间和精力组合
        for j in range(T + 1):
            for k in range(H + 1):
                # 不选择第 i 个事件
                dp[i][j][k] = dp[i - 1][j][k]
                # 选择第 i 个事件,如果满足时间和精力的限制
                if j >= time_required and k >= energy_required:
                    dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - time_required][k - energy_required] + happiness)

    # 返回最大快乐值,考虑所有事件和时间精力限制
    return dp[n][T][H]

# 测试样例
print(max_happiness(2, 2, 2, [1, 3], [3, 1], [3, 4]))  # 输出: 0
print(max_happiness(3, 5, 5, [2, 1, 3], [1, 3, 2], [10, 7, 8]))  # 输出: 18
print(max_happiness(1, 3, 3, [4], [4], [5]))  # 输出: 0

复杂度分析:

  • 时间复杂度O(n * T * H),其中 n 是事件的数量,T 是最大时间限制,H 是最大精力限制。
  • 空间复杂度O(n * T * H),因为我们需要一个三维数组来存储状态。

优化:

如果 T 和 H 较大时,使用三维 DP 数组会导致空间复杂度过高。可以考虑将 DP 数组优化为二维数组,使用滚动数组的技巧来降低空间复杂度:

def solution(n: int, T: int, H: int, t: list, h: list, a: list) -> int:
    # 初始化 DP 数组
    dp = [[0] * (H + 1) for _ in range(T + 1)]

    # 遍历每个事件
    for i in range(n):
        time_required = t[i]
        energy_required = h[i]
        happiness = a[i]

        # 逆向遍历时间和精力,防止当前事件重复计算
        for j in range(T, time_required - 1, -1):
            for k in range(H, energy_required - 1, -1):
                dp[j][k] = max(dp[j][k], dp[j - time_required][k - energy_required] + happiness)

    # 返回最大快乐值,考虑所有事件和时间精力限制
    return dp[T][H]

这种优化方法将 空间复杂度 降低为 O(T * H),但时间复杂度保持不变。