畜栏预定

题目

题目

做法

我们现在考虑一种贪心方法,我们把所有牛的按 l l l排序一遍,然后从小往大遍历,如果现在我的所有的畜栏都在工作,那么就新建一个畜栏,否则随便挑一个畜栏(反正都是没在工作,都一样),其实不难想是对的,但是严谨证明吗,我还是炒一下yxc大大的吧QMQ。


证明:

反证法,假设存在一种方案,使得需要的畜栏数量更少,记其需要的畜栏数量是 m m m

考虑在上述做法中,第一次新建第 m + 1 m+1 m+1 个畜栏的时刻,不妨设当前处理的是第 i i i 头牛。

由于所有牛是按开始时间从小到大排好序的,所以现在前 m m m 个畜栏中最后一头牛的开始时间一定小于等于第 i i i 头牛的开始时间。

而且前 m m m 个畜栏中最小的结束时间大于等于第 i i i 头牛的开始时间,所以前 mm 个畜栏里最后一头牛的吃草区间一定都包含第 i i i 头牛的开始时间,所以我们就找到了 m + 1 m+1 m+1 个区间存在交集,所以至少需要 m + 1 m+1 m+1 个畜栏,矛盾。

所以上述做法可以得到最优解,证毕。


当然,至于处理编号,以及看这个畜栏是否空闲,我是使用小根堆处理的,小根堆按照解放时间排序(即牛的结束时间+1)。

这里我又测试了一下,其实求最大覆盖数也能求出需要多少畜栏的,比如 [ 1 , 5 ] [1,5] [1,5] [ 2 , 6 ] [2,6] [2,6] [ 2 , 5 ] [2,5] [2,5]的覆盖数都是 2 2 2,所以答案是 2 2 2,其实也不难想,对于两个区间有交集,就说明它们不能再同一个畜栏里,所以如果最多 n n n个不能的话就要建立 n n n个畜栏的。(不知道怎么证明,知道的可以回复我一下,我写进博客里面,虽然我个人是觉得是对的。)

个人这里给出一个较伪的证明,对于 m m m个畜栏而言,我们考虑第二个栏中的每头牛,如果这头牛的区间和第一栏中没有一个是冲突的,就把它移动到第一栏中,这样第二栏的牛就在第一栏都有冲突了,第三栏则同时对一二栏做(优先对编号小的栏移动),这样第三栏的牛就在一二栏都存在冲突的牛(同时二对一也是如此,并没有改变),后面反复这样干,到了 n n n号栏就变成了至少存在一头牛使得 n n n个栏之间是冲突的。(如果不存在就至少会少一个栏。)

当然,这个做法并不能求编号,所以还是老老实实用前面的方法吧。

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

代码

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define  N  51000
#define  M  1100000 
using  namespace  std;
typedef  pair<int,int> PII;
struct  node
{
    
    
	int  l,r,id;
}a[N];int  n;
int  b[M],ans=0,an[N],fuck[N];
inline  bool  cmp(node  x,node  y){
    
    return  x.l<y.l;}
priority_queue<PII,vector<PII>,greater<PII> >c;//小根堆
int  list[N],top=0;
int  main()
{
    
    
	scanf("%d",&n);
	for(int  i=1;i<=n;i++){
    
    scanf("%d%d",&a[i].l,&a[i].r);a[i].id=i;}
	sort(a+1,a+n+1,cmp);
	for(int  i=1;i<=n;i++)
	{
    
    
		fuck[a[i].id]=i;
		while(!c.empty()  &&  c.top().first<=a[i].l)list[++top]=c.top().second,c.pop();
		if(top>0)an[i]=list[top--];
		else  an[i]=++ans;
		c.push(make_pair(a[i].r+1,an[i]));
	}
	printf("%d\n",ans);
	for(int  i=1;i<=n;i++)printf("%d\n",an[fuck[i]]);
	return  0;
}

实验代码,即测试后面那个想法是不是对的代码(当然是对的啦,不然也不会写了):

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define  N  51000
#define  M  1100000 
using  namespace  std;
typedef  pair<int,int> PII;
struct  node
{
    
    
	int  l,r,id;
}a[N];int  n;
int  b[M],ans=0,an[N],fuck[N];
inline  bool  cmp(node  x,node  y){
    
    return  x.l<y.l;}
priority_queue<PII,vector<PII>,greater<PII> >c;
int  list[N],top=0;

//试验区 
int  f[M];
inline  int  mymax(int  x,int  y){
    
    return  x>y?x:y;}
///
int  main()
{
    
    
	scanf("%d",&n);
	for(int  i=1;i<=n;i++){
    
    scanf("%d%d",&a[i].l,&a[i].r);a[i].id=i;f[a[i].l]++;f[a[i].r+1]--;}
	int  anss=0;
	for(int  i=1;i<=1000000;i++)anss=mymax(anss,f[i]+=f[i-1]);
	sort(a+1,a+n+1,cmp);
	for(int  i=1;i<=n;i++)
	{
    
    
		fuck[a[i].id]=i;
		while(!c.empty()  &&  c.top().first<=a[i].l)list[++top]=c.top().second,c.pop();
		if(top>0)an[i]=list[top--];
		else  an[i]=++ans;
		c.push(make_pair(a[i].r+1,an[i]));
	}
	printf("%d\n",anss);
	for(int  i=1;i<=n;i++)printf("%d\n",an[fuck[i]]);
	return  0;
}

小结

其实你会发现不管是这道题目还是上一道防晒,都是通过排序的方式解决到了 l l l或者 r r r,然后处理另外一个的。

猜你喜欢

转载自blog.csdn.net/zhangjianjunab/article/details/107746943