题目描述
小刚在玩 JSOI 提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T 部落消灭了所有 Z 部落的入侵者。但是 T 部落的基地里已经有 N 个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T 部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了
输入格式
第一行,一个整数 N。
接下来 N 行,每行两个整数 1,2T1,T2 描述一个建筑:修理这个建筑需要 1T1 秒,如果在 2T2 秒之内还没有修理完成,这个建筑就报废了。
输出格式
输出一个整数 S,表示最多可以抢修 S 个建筑。
。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
4
100 200
200 1300
1000 1250
2000 3200
3
对于这道题的总结如下:
-
显然, 先对报废时间晚 , 修复耗时短的建筑进行修复更优
则 可以先按照 报废时间 对各建筑进行排序 -
对于 已经选择的 一个任务序列
考虑 一个 新任务对 任务序列的影响 :-
如果 结束最后一个任务之后, 紧接着做新任务,可完成 新任务,
则 可以直接将 新任务 加入任务序列 , 显然较优 -
如果不满足上面的 情况 ,
但: 任务序列中 耗时最长的 任务 耗时>> 新任务显然 , 如果将 耗时长的任务 替换为新任务 ,
修复完成的 建筑数量不会改变 ,
但是 完成最后一个任务的时间右移 , 对之后加入的新任务更优
-
则可以按照上述结论进行贪心
对于 任务序列中 个任务的耗时, 可以使用堆维护。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 10;
int n;
struct node { int t1, t2; };
priority_queue<int>q;
node a[N];
bool cmp(const node& a, const node& b) {
return a.t2 > b.t2;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].t1>>a[i].t2;
}
sort(a + 1, a + 1 + n, cmp);
ll sum = 0;
ll tot = 0;
ll cnt = 0;
for (int i = 1; i <= n; i++) {
ll res = a[i].t1;
sum += res;
q.push(res);
if (sum <= a[i].t2) {
cnt++;
}
else{ sum -= q.top(); q.pop();}
}
cout << cnt << endl;
return 0;
}