HDU 6180 Schedule (贪心)
Description
给出\(n\)个加工任务的开始时间和结束时间,问最少要用多少台机器可以完成这些任务,同一台机器上的任务时间不能有重叠,但允许守尾相接。
Input
第一行给出用例组数\(T\),对于每组用例,第一行给出任务数量\(n\),接下来\(n\)行,每行给出两个整数,表示任务的开始时间和结束时间。\(1 \leqslant T \leqslant 100\),\(1 \leqslant n \leqslant 10^5\)。
Output
对于每组用例,输出两个整数,分别表示最少用的机器台数和所有机器用的总时间。一台机器的用时为它最后的结束时间减它最开始启动的时间,中间不会停机。
Sample Input
1
3
1 3
4 6
2 5
Sample Output
2 8
Solution
经典的任务分配问题。对所有的\(2n\)个时间点统一排序,如果时间点相同,就优先结束点在前,开始点在后。具体的实现可以对每个时间点存一个\(pair\),\(first\)为时刻值,开始点的\(second\)为\(1\),结束点的\(second\)为\(-1\)。
从前到后扫描\(2n\)个时间点,\(second\)的前缀和的最大值就是最少用的机器数量。
要求总用时,定于\(left[i]\)表示第\(i\)台机器的开始时间,\(right[i]\)表示第\(i\)台机器当前到的时间,\(left[i]\)在第一次用到\(i\)机器时记录,\(right[i]\)随扫描的进行不断更新,当扫描到一个结束点时,说明当前的机器要结束,先更新\(right[i]\)的值,计数器再减一。扫描结束后\(right\)数组中存储的就是每台机器最终的结束时间。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
typedef pair<int, int> pii;
pii a[2 * N];
int l[N], r[N];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
int left, right;
scanf("%d%d", &left, &right);
a[2 * i - 1] = pii(left, 1);
a[2 * i] = pii(right, -1);
}
sort(a + 1, a + 2 * n + 1);
memset(l, -1, sizeof(l));
memset(r, -1, sizeof(r));
int num = 0, ans = 0;
for (int i = 1; i <= 2 * n; i++)
{
if (a[i].second == 1)
{
num++;
if (l[num] == -1) l[num] = r[num] = a[i].first;
ans = max(ans, num);
}
else
{
r[num] = a[i].first;
num--;
}
}
ll sum = 0;
for (int i = 1; i <= ans; i++) sum += r[i] - l[i];
printf("%d %lld\n", ans, sum);
}
return 0;
}