题目链接

【模板】二维费用背包

题目描述

小红有 个事件可以分享。对于第 个事件,分享需要花费 分钟时间和 点精力,并能获得 点快乐值。小红希望在总耗时不超过 ,总消耗精力不超过 的前提下,选择分享若干事件,使得获得的快乐值总和最大。

输入:

  • 第一行输入一个整数 ,表示事件数量。
  • 第二行输入两个整数 ,表示可用时间和可用精力的上限。
  • 接下来 行,每行输入三个整数 ,描述第 个事件的参数。

输出:

  • 输出一个整数,代表在限制条件内能获得的最大快乐值。

解题思路

本题是一个典型的 二维费用01背包问题。与传统的01背包问题不同,这里每个物品(事件)有两个“费用”或“成本”(时间和精力),而我们要在两个限制条件下求最大价值。

  1. 状态定义:

    • 我们定义一个二维数组 ,其中 表示在时间限制为 、精力限制为 的情况下,所能获得的最大快乐值。
  2. 状态转移:

    • 对于第 个事件(耗时 ,耗精力 ,快乐值 ),我们有两种选择:
      • 不选择 该事件:最大快乐值保持不变,与只考虑前 个事件时相同。
      • 选择 该事件:前提是当前的时间和精力预算足够,即 。如果选择,那么快乐值就是在消耗 时间和 精力前的最大快乐值(即 )基础上,加上当前事件的快乐值
    • 因此,状态转移方程为:
  3. 遍历顺序:

    • 为了确保每个事件最多只被选择一次(01背包的特性),我们需要对时间和精力这两个维度进行 逆序遍历
    • 遍历顺序如下:
      • 外层循环遍历每个事件
      • 中层循环遍历时间
      • 内层循环遍历精力
  4. 初始化:

    • 我们需要将 数组全部初始化为0,表示在没有任何预算或不选择任何事件时,快乐值为0。

最终, 就是我们要求的答案。

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int N;
    cin >> N;
    int T, H;
    cin >> T >> H;

    vector<vector<long long>> dp(T + 1, vector<long long>(H + 1, 0));

    for (int i = 0; i < N; ++i) {
        int t, h, p;
        cin >> t >> h >> p;
        for (int j = T; j >= t; --j) {
            for (int k = H; k >= h; --k) {
                dp[j][k] = max(dp[j][k], dp[j - t][k - h] + p);
            }
        }
    }

    cout << dp[T][H] << "\n";
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int T = sc.nextInt();
        int H = sc.nextInt();

        long[][] dp = new long[T + 1][H + 1];

        for (int i = 0; i < N; i++) {
            int t = sc.nextInt();
            int h = sc.nextInt();
            int p = sc.nextInt();
            for (int j = T; j >= t; j--) {
                for (int k = H; k >= h; k--) {
                    dp[j][k] = Math.max(dp[j][k], dp[j - t][k - h] + p);
                }
            }
        }

        System.out.println(dp[T][H]);
    }
}
N = int(input())
T, H = map(int, input().split())

dp = [[0] * (H + 1) for _ in range(T + 1)]

for _ in range(N):
    t, h, p = map(int, input().split())
    for j in range(T, t - 1, -1):
        for k in range(H, h - 1, -1):
            dp[j][k] = max(dp[j][k], dp[j - t][k - h] + p)

print(dp[T][H])

算法及复杂度

  • 算法:动态规划 (二维费用01背包)
  • 时间复杂度: - 我们需要遍历 个事件,对于每个事件,都需要更新大小为 表。
  • 空间复杂度: - 主要开销是 二维数组。