题意:有一些任务,要用一些机器去做这些任务,给出每个任务的开始时间和结束时间。一台机器最多只能同时做一个任务,并且机器关掉不能再开,求在使用最少机器的情况下,最少的机器个数和最短的运行时间。
拿两个优先队列模拟…贪心的找现在空着的机器中做完上个任务最晚的那个,这样才能让机器等的时间最少。
代码里有详细解释。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
int N;
ll cnt,sum;
struct Work{
ll start,end;
}work[100000+10];
bool cmp(Work a,Work b){
if (a.start!=b.start)
return a.start<b.start;
else
return a.end<b.end;
}
// 空闲序列其实表示的是所有已经开始运行但现在没有任务在运行的机器
priority_queue < ll,vector<ll>,greater<ll> > working; // 小顶堆,工作机器序列
priority_queue < ll,vector<ll>,less<ll> > notworking; // 大顶堆,空闲机器序列
int main(){
// freopen("1.txt","r",stdin);
scanf("%d",&T);
while (T--){
while (!working.empty()) working.pop();
while (!notworking.empty()) notworking.pop();
cnt=0;
sum=0;
scanf("%d",&N);
for (int i=1;i<=N;i++){
scanf("%lld %lld",&work[i].start,&work[i].end);
}
sort(work+1,work+N+1,cmp);
for (int i=1;i<=N;i++){
// 从运行序列中找出所有比当前任务的开始时间早的
// 也就是在当前任务开始前就已经完成了的加入空闲集合
while (!working.empty()&&working.top()<=work[i].start){
ll tmp=working.top();
working.pop();
notworking.push(tmp);
}
// 如果此时空闲集合不为空,说明这个机器开着但是现在没有任务可做
// 那么肯定是优先选择做完上个任务的时间晚的来做这个任务
// 这样机器等的时间就少
if (!notworking.empty()){
ll tmp=notworking.top();
notworking.pop();
sum+=work[i].end-tmp; // 加上机器等的时间和做这个任务的时间
working.push(work[i].end); // 加入运行序列
}
// 若果此时空闲集合为空,说明现在没有机器,那只能新开一台机器
else{
cnt++; // 新开一台机器
sum+=work[i].end-work[i].start; // 加上做这个任务的时间
working.push(work[i].end); // 加入运行序列
}
}
printf("%lld %lld\n",cnt,sum);
}
}