Stall Reservations
Oh those picky N (1 <= N <= 50,000) cows! They are so picky that each one will only be milked over some precise time interval A..B (1 <= A <= B <= 1,000,000), which includes both times A and B. Obviously, FJ must create a reservation system to determine which stall each cow can be assigned for her milking time. Of course, no cow will share such a private moment with other cows.
Help FJ by determining:
- The minimum number of stalls required in the barn so that each cow can have her private milking period
- An assignment of cows to these stalls over time
Many answers are correct for each test dataset; a program will grade your answer.
Input
Line 1: A single integer, N
Lines 2..N+1: Line i+1 describes cow i‘s milking interval with two space-separated integers.
Output
Line 1: The minimum number of stalls the barn must have.
Lines 2..N+1: Line i+1 describes the stall to which cow i will be assigned for her milking period.
Sample Input
5 1 10 2 4 3 6 5 8 4 7
Sample Output
4 1 2 3 2 4
Hint
Explanation of the sample:
Here‘s a graphical schedule for this output:
Time 1 2 3 4 5 6 7 8 9 10 Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>> Stall 2 .. c2>>>>>> c4>>>>>>>>> .. .. Stall 3 .. .. c3>>>>>>>>> .. .. .. .. Stall 4 .. .. .. c5>>>>>>>>> .. .. ..
Other outputs using the same number of stalls are possible.
这道题是讲怎么把找到区间最大覆盖并且把每个牛的所在的机器也要一并求出。要是只求出最大覆盖数以及其区间我们可以设置一个diff数组用于存放该时间段与上一个时间段的差值,这样在加入一个时间段时只要修改起始时间的diff(起始时间比原来加一了,所以该加一)和结束后一个时间的diff(因为结束时间的覆盖数加一了,所以下一个与它的差值应该减一)即可,因为之间的时间差值并未发生变化。最后在O(n)遍历一边求得最大值即可。
但是本题不行,因为还要求出每头牛使用的机器号。那我们就采用贪心策略进行解决。
因为每次肯定是起始时间靠前的去找FJ取奶,所以我们排序要按照起始时间靠前的排列,每次FJ应当判断所有的机器中当前最早结束的结束时间是不是比要加进去的牛的起始时间早,因为如果最早结束都晚了,其他的肯定不可能,那么FJ就要再去买一台机器。如果可以呢?那我们就放到某台机器中去。由于在所有的机器中,能放下那头牛的机器(可能不止一台)集合实际上的有效时间都是一样的,只要能放,不管之前那台机器的结束时间最早还是不最早,其实都是没有影响的,因为能放的机器集合有效时段都是从本头牛的起始时间(因为之后的牛必大于等于这个起始时间,因为排序就这么排的)到所有牛里面的最晚结束时间,但是我们既然比较了最早结束且能放,那我们就用它咯!
于是乎我们得到这样解决问题的算法:我们建立一个优先队列(能插入时O(logn)排好序),找到我们要的当前最早结束的机器,然后将结束时间与当前想要挤奶的奶牛的起始时间进行比较,如果能放进去,那么那个奶牛使用的机器号就是那个最早结束的机器号,由于奶牛进去后该台机器的结束时间不再是以前的时间了,所以我们把第一的那台机器的时间pop掉,由于新加进去的奶牛的结束时间为该台机器新的结束时间,我们把奶牛放进队列,实际上也是把该台机器新的结束时间放进队列;如果不能放进去,那FJ就要买一台机器放进去,同样那台机器的结束时间就是那头牛的结束时间。由于新机器里面只有一头牛,该牛的结束时间为该机器的结束时间,若下次放第二头则第一头pop,第三头则第二头pop所以其实队列的元素个数也就是机器的数量(因为每台机器这样操作只能留一头,也就是最近加进来的那一头,之前的被pop了,新机器不会pop但是也是只有一头),所以队列的优先既是每台机器最近的奶牛的结束时间的最小值,也是每台机器结束时间的最小值。
AC代码(思路来源:https://blog.csdn.net/u014303647/article/details/38342603):
#include <stdio.h> #include <queue> #include <algorithm> using namespace std; struct Node{ int s; int e; int i; friend bool operator <(Node x, Node y) { return x.e > y.e; } }cows[50005]; bool cmp (Node x, Node y) { return x.s < y.s; } int order[50005]; priority_queue<Node> pq; int ans; int main(void) { int n; scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%d %d", &cows[i].s, &cows[i].e); cows[i].i = i; } sort(cows, cows + n, cmp); pq.push(cows[0]); ans = 1; order[cows[0].i] = 1; for(int i = 1; i < n; i++) { if(!pq.empty() && pq.top().e < cows[i].s)//能把A牛放在B机器中(A牛:新加牛,B机器:当前最早结束的机器) { order[cows[i].i] = order[pq.top().i];//新加入的牛A使用的机器号就是B,而B就是当前所有机器最早结束的牛的机器号 pq.pop();//B原来的牛不能代表B的结束时间了,pop掉 } else { ans++;//FJ买了新的机器 order[cows[i].i] = ans;//新的机器号放的当然是新加入的牛 } pq.push(cows[i]);//把牛(实际上是选中放这头牛的机器的结束时间)放入队列中 } printf("%d\n", ans); for(int i = 0; i < n; i++) printf("%d\n", order[i]); while(!pq.empty()) pq.pop(); return 0; }
原文地址:https://www.cnblogs.com/jacobfun/p/12200429.html