题目链接:点击打开链接
题目大意:有n个任务,每个任务有3个参数,r d w,表示要在时刻r和d之内执行完毕,工作量为w。当执行速度为s时,工作量为w的任务需要w/s个单位时间。任务可以分块执行。你需要求出处理器执行过程中最大速度的最小值,保证每个任务都能在规定时间段内完成。
思路:二分法 贪心
分析:
1. 这种类型的题应该用二分答案来做
2. 对于每次二分得到的结果应该做个判断看合不合适。办法就是定一个优先队列,每过一段时间新到达的任务以结束时间为优先级加入队列,结束时间靠前的排前面。最后看这个队列中的任务能不能在规定时间段内完成(移出队列)
3. 思路过于冗余了,其实还有更巧妙的方法。速度为s表示一个单位时间内可以完成s个工作量,从这个角度考虑,代码会更简洁清晰。毕竟还是图样。
代码:
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXS = 10000000;
const int maxn = 10000 + 10;
int n;
double last_finish;
struct task
{
double r, d, w;
bool operator < (const task& t) const
{
return d > t.d;
}
};
task t_array[maxn];
bool comp(const task& t1, const task& t2)
{
return t1.r < t2.r;
}
bool ok(int s)
{
priority_queue<task> arrive_list; // 存放某时刻为止到达的所有任务,结束时间靠前的排前面
double now_time = t_array[0].r, next_time; // 当前时刻和下个到达时刻
int i = 0;
while (1)
{
for (; i < n && t_array[i].r <= now_time; ++i)
arrive_list.push(t_array[i]);
next_time = i < n ? t_array[i].r : last_finish; // 如果所有任务都已经进了队列,那么下个到达时刻为最终结束时刻
task t = arrive_list.top();
arrive_list.pop();
double finish_time = now_time + t.w / s;
// 调度失败
if (finish_time > t.d)
return false;
// 在下个任务到达时没能完成当前任务
if (finish_time > next_time)
{
finish_time = next_time;
t.w -= s * (finish_time - now_time);
arrive_list.push(t);
}
now_time = finish_time;
if (arrive_list.empty()) {
if (i == n)
return true;
else
now_time = next_time;
}
}
}
void init()
{
scanf("%d", &n);
last_finish = 0;
for (int i = 0; i < n; i++)
{
scanf("%lf %lf %lf", &t_array[i].r, &t_array[i].d, &t_array[i].w);
last_finish = max(last_finish, t_array[i].d);
}
sort(t_array, t_array+n, comp);
}
void solve()
{
int L = 1, R = MAXS;
while (L < R)
{
int M = (L + R) / 2;
if (ok(M)) R = M; else L = M + 1;
}
printf("%d\n", L);
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
init();
solve();
}
return 0;
}