01背包-蓝桥课程抢购

题目描述

为了能让更多的同学学习到 IT 技术,蓝桥云课又开始了课程限时打折活动!

作为初学者的你,希望尽可能买到含金量总额更高的课程,当然其他同学也是这么想。

由于购买课程的同学实在太多,蓝桥云课服务器带宽供不应求,导致同学购买课程需要一定的等待时间。

比如现有三门课程:

  • 《Java 程序设计》需要等待 3 分钟,打折活动在 3 分钟后结束,该课程含金量为 6。
  • 《Python 程序设计》需要等待 2 分钟,打折活动在 2 分钟后结束,该课程含金量为 3。
  • 《C#程序设计》需要等待 1 分钟,打折活动在 3 分钟后结束,该课程含金量为 5。

方案一:你可以选择购买《Java 程序设计》,那么你可以抢购到含金量为 6 的课程。

方案二:你可以先购买《Python 程序设计》,等待结束后再购买《C#程序设计》,这样就可以抢购到含金量为 8 的课程。

请注意,只能同时参与一门课程的抢购活动,且开始等待后不允许中途退出,只有在打折活动有效期内才可以抢购课程。

输入格式

第一行是一个整数 N,代表蓝桥云课中有 N 门课程。

紧接着 N 行,每行三个正整数,A(购课等待时间),B(打折活动截止时间),C(课程含金量)。

输出格式

输出一行一个整数,代表你能购买到课程最大的含金量总值。

样例输入

3
3 3 6
2 2 3
1 3 5

样例输出

8

评测数据规模

对于 20% 的评测数据,

  • 0 < N < 10
  • 1 < A < 20
  • 1 < B < 20
  • 1 < C < 20,且 A ≤ B

对于所有评测数据,

  • 0 < N ≤ 50
  • 1 < A < 10^5
  • 1 < B < 10^5
  • 1 < C < 2^31,且 A ≤ B

题解

这个问题本质上是一个 时间背包问题(Time-Constrained Knapsack),类似于 0-1 背包问题,但物品(课程)有时间约束,不能随时选择。
这个问题可以通过动态规划来解决。我们需要找到一种策略,在有限的时间内最大化所购得课程的含金量。具体步骤如下:

  1. 初始化

    • 定义一个动态规划数组 dp[],其中 dp[j] 表示在第 j 分钟所能获得的最大含金量。
    • 初始化时,假设所有元素都为0,表示没有进行任何购买操作。
  2. 排序与处理

    • 将所有课程按其打折活动截止时间 B 进行升序排序,如果 B 相同则按等待时间 A 升序排序。
  3. 状态转移

    • 对于每一个课程,从其截止时间 B 开始向前遍历至其等待时间 A,更新 dp[j] 的值,即考虑是否选择当前课程以增加总含金量。
  4. 结果计算

    • 最终,遍历整个 dp[] 数组,找到最大值即为能获得的最大含金量。

    注意
    排序的原因是 b(截止时间)不同,避免状态污染。
    维护 mc = max(mc, dp[j]) 的原因是 a(等待时间)存在,最优值可能在 b_max 之前的某个 j 处。

示例代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int N = 1e5 + 9;

ll dp[N]; // 在j分钟后所能购得的最大含金量

struct node{
    int a, b, c;
    bool operator < (const node &u)const{
        return b == u.b ? a < u.a : b < u.b;
    }
}x[N];

int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n; cin >> n;
    for(int i = 1;i <= n;i ++) cin >> x[i].a >> x[i].b >> x[i].c;
    ll mc = -1;
    sort(x + 1, x + n + 1);
    for(int i = 1;i <= n;i ++){
        for(int j = x[i].b;j >= x[i].a;j --){
            dp[j] = max(dp[j], dp[j - x[i].a] + x[i].c);
            mc = max(mc, dp[j]);
        }
    }
    cout << mc << '\n'; 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值