4144.畜栏保留问题
总时间限制: 1000ms 内存限制: 65536kB
描述
农场有N头牛,每头牛会在一个特定的时间区间[A, B](包括A和B)在畜栏里挤奶,且一个畜栏里同时只能有一头牛在挤奶。现在农场主希望知道最少几个畜栏能满足上述要求,并要求给出每头牛被安排的方案。对于多种可行方案,主要输出一种即可。
输入
输入的第一行包含一个整数N(1 ≤ N ≤ 50, 000),表示有N牛头;接下来N行每行包含两个数,分别表示这头牛的挤奶时间[Ai, Bi](1 ≤ A≤ B ≤ 1, 000, 000)。
输出
输出的第一行包含一个整数,表示最少需要的畜栏数;接下来N行,第i+1行描述了第i头牛所被分配的畜栏编号(从1开始)。
样例输入
5
1 10
2 4
3 6
5 8
4 7
样例输出
4
1
2
3
2
4
分析
贪心策略
最大限度利用已有的畜栏。
- 把n头牛按照开始时间排序;
- 为第1头牛新建一个畜栏,记录其结束时间;
- 对于第i头牛,找到已有的畜栏中结束时间最早的,并与它自己的开始时间比较。
- 如果开始时间大于(注意这里是严格大于,之前自以为是大于等于然后一直WA嘤嘤嘤┭┮﹏┭┮)最早的结束时间,就把牛i安排到那个畜栏里面,把原来的牛j“丢出来”;如果小于等于,就新建一个畜栏。更新结束时间。
贪心策略正确性的证明
假设用以上贪心策略对前n头牛的安排方案至少和最优策略用的畜栏数相同,并且该方案具有最小的最早结束时间。
- 当n=1时,结论显然成立;
- 假设当n=k时也成立,那么对于k+1头牛:
① 证明贪心策略对前n头牛的安排方案至少和最优策略用的畜栏数相同:
(反证法)若畜栏数不是最优的,已知k头牛的最优策略的畜栏数就是上述贪心策略得到的,那么前k+1头牛的最优策略不会小于这个数;
又因为结论不成立,所以一定是——
贪心策略:放入第k+1头牛的时候,它的开始时间Ak+1小于前k头牛贪心策略得到的最早结束时间Tk,新建了一个畜栏;
最优策略:放入第k+1头牛的时候,它的开始时间大于等于前k头牛最优策略得到的最早结束时间T’k,放入了已有的畜栏;
也就是T’k<=Ak+1<Tk——这与归纳假设中前k头牛的贪心策略具有最小的最早结束时间矛盾!
② 证明贪心策略具有最小的最早结束时间:
当第k+1头牛的开始时间小于最小的最早结束时间,就新建一个畜栏,这是最早结束时间更新为第k+1头牛的结束时间(如果它比原有的更小),或者保持原来的最小最早结束时间不变;
否则,放入相应的畜栏,在所有的畜栏的结束时间中找到最小的,更新最早结束时间。
上述每一种更新,都保证了最早的结束时间是最小的。
贪心的实现
- 按照开始时间排序所有的牛;
- 用优先队列维护已有畜栏,保证堆顶的畜栏具有最小的最早结束时间;
对于一头新的牛,要么把原有的牛弹出,再放入自己(相当于更新了原有的畜栏的状态),要么直接放入自己(相当于新建了一个畜栏)。 - 注意此时的运算符重载在结构体内部
代码及解析
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 50010
struct cattle//定义结构体,l,r分别表示牛挤奶的开始、结束时间,id表示第i头牛
{
int l