题意:
有 n 个任务,每个任务有 3 个参数,r, d,w。表示必须在时间 [ r, d ] 之内执行,任务量为 w。
处理器的执行速度可以变化,当速度为 s 时,一工作量为 w 的任务要执行 w / s 个单位时间。任务不一定连续执行,
可以分块执行,求最小完成任务的速度。速度可以是任意整数。
分析:
先将这些任务按开始时间由小到大排序,模拟处理器按时间处理任务。然后二分法求最优解。
求解时枚举每个单位时间,将满足条件的任务放入优先队列,结束时间(d)越小越先出队列,因为要把 d 小的先完成。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#define for1(i, a, b) for(int i = a; i <= b; i++)
using namespace std;
const int maxn = 10000 + 10;
int n;
struct Work
{
int r, d, w;
friend bool operator < (Work a, Work b) { //优先队列中的 work,d 越小越先出队列
return a.d > b.d;
}
} work[maxn];
bool cmp(Work a, Work b)
{
return a.r < b.r;
}
bool cleck(int cur)
{
priority_queue<Work> Q;
int c = 0;
for1(i, 1, 20000){
int sum = cur;
while(work[c].r < i && c != n) Q.push(work[c++]);
while(sum && !Q.empty()){
Work cnt = Q.top();
Q.pop();
if(cnt.d < i) return false; //当前任务的结束时间小于此时刻,这个速度完不成!
if(cnt.w > sum){ //此单位时间不能做完当前任务
cnt.w -= sum; //能做多少做多少
sum = 0;
Q.push(cnt); //放入队列,下次再做
}
else{ //能完成当前任务
sum -= cnt.w;
}
}
if(c == n && Q.empty()) return true; //全部任务都完成
}
if(c == n && Q.empty()) return true;
return false;
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for1(i, 0, n-1) scanf("%d%d%d", &work[i].r, &work[i].d, &work[i].w);
sort(work, work + n, cmp); //先按开始时间由小到大排序
int L = 0, R = 10000000; //n最大为10000,w最大为1000,故最大速度为10000000
while(L < R){ //二分求最优解
if(L == R - 1) break;
int D = (L + R) >> 1;
if(cleck(D)) R = D;
else L = D;
}
printf("%d\n", R);
}
return 0;
}