题目描述:
题目链接
有 n(n≤800000) 个工作,已知每个工作需要的时间 qi 和截止时间 di (不必在此之前完成),最多能完成多少个工作?工作只能串行完成。第一项任务开始的时间不早于时刻 0 。
—-摘自《算法竞赛入门经典》
算法:
贪心
做法:
可以想到的是如果知道了要完成的这些工作,那么就应该不停歇的把工作完成,即两个工作之间不应有空闲,这是最优的。
把所有工作按 d 从前往后排序,记录一个
t
代表已用的时间。现在要处理第 i 个任务,如果
t+qi≤di
,那么就“暂时”完成这个工作;如果
t+qi>di
,就看看之前完成的工作中耗时最多的那个
j
,如果 dj>di ,那么就可以撤销
j
,换成 i ,因为耗时长又截止时间短的工作不如耗时短而截止时间长的工作。
我为什么想不到呢?
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=800010;
int n, T;
struct Work{
int q, d;
bool operator < (const Work & rhs) const {
return d<rhs.d;
}
} w[N];
int ans = 0 , t;
priority_queue <int> Q; // 用优先队列找到已完成的耗时最长的工作的耗时
int main(){
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=1; i<=n; ++i) scanf("%d%d", &w[i].q, &w[i].d);
sort(w+1, w+n+1);
t = 0;
while(!Q.empty()) Q.pop();
for(int i=1; i<=n; ++i){
if(t+w[i].q<=w[i].d){
Q.push(w[i].q);
t += w[i].q;
}else{
if(!Q.empty() && Q.top()>w[i].q){
t = t-Q.top()+w[i].q;
Q.pop();
Q.push(w[i].q);
}
}
}
printf("%d\n", Q.size());
if(T) puts("");
}
while(1);
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=800010;
int n, T;
struct Work{
int q, d;
bool operator < (const Work & rhs) const {
return d<rhs.d;
}
} w[N];
int ans = 0 , t;
priority_queue <int> Q; // 用优先队列找到已完成的耗时最长的工作的耗时
int main(){
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=1; i<=n; ++i) scanf("%d%d", &w[i].q, &w[i].d);
sort(w+1, w+n+1);
t = 0;
while(!Q.empty()) Q.pop();
for(int i=1; i<=n; ++i){
if(t+w[i].q<=w[i].d){
Q.push(w[i].q);
t += w[i].q;
}else{
if(!Q.empty() && Q.top()>w[i].q){
t = t-Q.top()+w[i].q;
Q.pop();
Q.push(w[i].q);
}
}
}
printf("%d\n", Q.size());
if(T) puts("");
}
while(1);
}