Schedule
Problem Description
There are N schedules, the i-th schedule has start time
si
and end time
ei
(1 <= i <= N). There are some machines. Each two overlapping schedules cannot be performed in the same machine. For each machine the working time is defined as the difference between
timeend
and
timestart
, where time_{end} is time to turn off the machine and
timestart
is time to turn on the machine. We assume that the machine cannot be turned off between the
timestart
and the
timeend
.
Print the minimum number K of the machines for performing all schedules, and when only uses K machines, print the minimum sum of all working times.
Print the minimum number K of the machines for performing all schedules, and when only uses K machines, print the minimum sum of all working times.
Input
The first line contains an integer T (1 <= T <= 100), the number of test cases. Each case begins with a line containing one integer N (0 < N <= 100000). Each of the next N lines contains two integers
si
and
ei
(0<=si<ei<=1e9)
.
Output
For each test case, print the minimum possible number of machines and the minimum sum of all working times.
Sample Input
1 3 1 3 4 6 2 5
Sample Output
2 8
Source
题意:给你一堆需要全部完成工作(时间区间),每台机器同时只能做一份工作,并且机器开机后,除非做完最后一个作业,不然不关机(题目没说清楚……还是我英语太差了)。求在最少机器数的情况下,最少的工作的总时间。两者都要输出。
解题思路:一开始一看这不很简单的问题吗!想了各种数据结构,试了下优先队列,但是发现优先队列不能二分,后来想起来set可以二分,然后写了半天,调试了很久,一开始想着用set存区间,然后发现排序的时候和二分的时候出现各种问题,最后想到set其实直接存结束时间就好了,根本不用存区间。然后就写好了。结果各种超时……怀疑人生……最后优化到极点……才过了…………原来Algorithm里面的二分比set自带的二分要慢很多……记住了……
思路其实很简单,首先按照开始时间排序,一个一个工作的扫过去,对于每一个工作,找到结束时间最晚的并且小于等于这个工作的开始时间,让这个机器做这个工作就可以了。这里可以用二分。WA的应该都是这组数据,因为他要求最小时间,必须让结束时间最晚并且小于等于这个工作的开始时间的那个机器做这个工作。
应该还会有O(n)的做法……
1
3
1 5
2 6
8 10
应该输出2 12
#include<iostream>
#include<deque>
#include<memory.h>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<list>
#include<queue>
#include<set>
#define INF (1LL<<62)
#define ll long long int
using namespace std;
//输入挂,不然超时
int Scan(){
int res = 0, flag = 0;
char ch;
if ((ch = getchar()) == '-'){
flag = 1;
}
else if(ch >= '0' && ch <= '9'){
res = ch - '0';
}
while ((ch = getchar()) >= '0' && ch <= '9'){
res = res * 10 + (ch - '0');
}
return flag ? -res : res;
}
struct qujian{
int l;
int r;
}qs[100005];
bool cmp(qujian a,qujian b){
return a.l<b.l;//按照开始时间排序
}
multiset<int> s; //一定要定义在外面,不然超时
int N;
int main()
{
int t=Scan();
while(t--){
N=Scan();
for(int i=0;i<N;i++){
qs[i].l=Scan();
qs[i].r=Scan();
}
sort(qs,qs+N,cmp);
ll ans=0;
s.clear();//s存所有机器的结束时间
for(int i=0;i<N;i++){
// multiset<int>::iterator it=upper_bound(s.begin(),s.end(),qs[i].l);//algorithm的二分超时!要用Set自带的
multiset<int>::iterator it=s.upper_bound(qs[i].l);
if(it==s.begin())//如果比所有都要小,那么只能新开一个机器了
{
ans+=qs[i].r-qs[i].l;//记录答案
s.insert(qs[i].r);
}
else{
it--;//细节
//要把这两句合并,不然超时!这就是传说中的卡常数吗
// ans+=qs[i].l-*it;//空隙部分
// ans+=qs[i].r-qs[i].l;//当前工作的时间
ans+=qs[i].r-*it;
s.erase(it);
s.insert(qs[i].r);
}
}
printf("%d %I64d\n",s.size(),ans);
}
return 0;
}