zoukankan      html  css  js  c++  java
  • 畜栏预定

    题目

    题目

    做法

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


    证明:

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

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

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

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

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


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

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

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

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

    时间复杂度:(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
    ",ans);
    	for(int  i=1;i<=n;i++)printf("%d
    ",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
    ",anss);
    	for(int  i=1;i<=n;i++)printf("%d
    ",an[fuck[i]]);
    	return  0;
    }
    

    小结

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

  • 相关阅读:
    厦门航空牵手阿里云打造航空业移动研发中台,研发效率提升50%
    可能是国内第一篇全面解读 Java 现状及趋势的文章
    这样才能正确解锁MaxCompute客户端
    MaxCompute问答整理之10月
    tensorflow入门
    buctoj——合法的出栈顺序
    nyoj299——如何优雅的写矩阵快速幂
    nyoj164——卡特兰数(待填坑)
    nyoj139——康托展开
    字符串练习
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13419686.html
Copyright © 2011-2022 走看看