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),然后处理另外一个的。

  • 相关阅读:
    python中list/tuple/dict/set的区别
    jquery修改ajax的header的字段origin方法,均被浏览器拒绝
    js判断上传文件的大小、类型、修改日期等信息
    js调试方法
    sqlmapapi的跨域访问Access-Control-Allow-Origin:*;ajax
    flask的文件上传和下载
    flask中的g、add_url_rule、send_from_directory、static_url_path、static_folder的用法
    python读写csv时中文乱码问题解决办法
    css中!important的作用
    项目经验——Sql server 数据库的备份和还原____还原数据库提示“介质集有2个介质簇,但只提供了1个。必须提供所有成员” .
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13419686.html
Copyright © 2011-2022 走看看