[反悔贪心 C++] 洛谷P4053 [JSOI2007] 建筑抢修

173 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

题目描述

小刚在玩 JSOI 提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T 部落消灭了所有 Z 部落的入侵者。但是 T 部落的基地里已经有 NN 个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T 部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。

输入输出格式

输入格式

第一行,一个整数 NN。 接下来 NN 行,每行两个整数 T1,T2T_1,T_2 描述一个建筑:修理这个建筑需要 T1T_1 秒,如果在 T2T_2 秒之内还没有修理完成,这个建筑就报废了。

输出格式

输出一个整数 SS,表示最多可以抢修 SS 个建筑。

输入输出样例

输入样例 #1

4
100 200
200 1300
1000 1250
2000 3200

输出样例 #1

3

解题思路

首先,我们需要把所有数按照t2t_2进行升序排序,从而确定修理建筑的先后顺序。

但仅仅这样贪心不一定是最优的,需要在中途进行转正。

排序之后,我们从1n遍历一遍建筑,确定这个建筑是否需要修理。

显然,如果可以在这个建筑报废之前修理好它,则一定修。

否则的话,则一定会报废一个建筑。显然,要报废的建筑的是修理时间最长的建筑。

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

int main()
{
    int n;
    cin >> n;
    vector<pair<int,int>> vp(n);
    for(auto& [T1, T2] : vp) cin >> T1>> T2;
    sort(vp.begin(), vp.end(), [&](const auto& x, const auto& y) {
       return x.second < y.second; 
    });
    priority_queue<int> pq;
    int ret = 0, now = 0;
    for(const auto& [T1, T2] : vp) {
        if(now + T1 <= T2) {
            now += T1, ret += 1;
            pq.push(T1);
        }
        else if(T1 < pq.top()) {
            now = (now - pq.top()) + T1;
            pq.pop();
            pq.push(T1);
        }
    }
    cout << ret << endl;
    return 0;
}