3个典型区间贪心问题(总结篇)

  1.数轴上有n个闭区间[ai,bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。

  2.数轴上有n个开区间(ai,bi)。最多能有多少个互不相交的区间?

  3.数轴上有n个区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]。

  解法:

        1.

          贪心策略:

          按照b1<=b2<=b3…(b相同时按a从大到小)的方式排序排序,从前向后遍历,当遇到没有加入集合的区间时,选取这个区间的右端点b。

          代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef struct node
{
         int l,r;
}node;
node p[100005];
bool cmp(node a,node b){
         return a.r<b.r;
}
int main()
{
         int T;
         scanf("%d",&T);
         while(T--){
                  int n;
                  scanf("%d",&n);
                  for(int i=0;i<n;i++)
                           scanf("%d%d",&p[i].l,&p[i].r);
                  sort(p,p+n,cmp);
                  int now=-1;
                  int ans=0;
                  for(int i=0;i<n;i++){
                           if(p[i].l>now){
                                    now=p[i].r;
                                    ans++;
                           }
                  }
                  printf("%d\n",ans);
         }
         return 0;
}
       2. 

       贪心策略:

       按照b1<=b2<=b3…的方式排序,然后从前向后遍历,每当遇到可以加入集合的区间,就把它加入集合。(集合代表解的集合)

       代码:

    #include <stdio.h>  
    #include <algorithm>  
    using namespace std;  
    struct Extent  
    {  
        int a,b;  
        bool operator < (const Extent& S)const  
        {  
            return b < S.b;  
        }  
    }A[10002];  
    int main()  
    {  
        int z,n,cnt,end;  
        scanf("%d",&z);  
        while(z--)  
        {  
            cnt = 0;  
            end = -1;  
            scanf("%d",&n);  
            for(int i=0;i<n;i++)  
                scanf("%d%d",&A[i].a,&A[i].b);  
            sort(A,A+n);  
            for(int i=0;i<n;i++)  
            {  
                if(end < A[i].a)  
                {  
                    end = A[i].b;  
                    cnt++;  
                }  
            }  
            printf("%d\n",cnt);  
        }  
        return 0;  
    }  
    3.

     贪心策略:

     把各区间按照a从小到大排序,从前向后遍历,然后每次选择从当前起点S开始的最长区间,并以这个区间的右端点为新的起点,继续选择,直到找不到区间覆盖当前起点S或者S已经到达线段末端。

需要注意的是,如果某一区间边界大于s,t的边界,应把它们变成s或t。因为超出的部分毫无意义,同时还会影响对数据的分析。

代码:

    #include <math.h>  
    #include <stdio.h>  
    #include <algorithm>  
    using namespace std;  
    struct Qujian  
    {  
        float a,b;  
    };  
    bool cmp(const Qujian& s1,const Qujian& s2)  
    {  
        return s1.a < s2.a;  
    }  
    int main()  
    {  
        Qujian A[10005];  
        int z,n,w,h,x,r,cnt;  
        float start,l,__h;  
        scanf("%d",&z);  
        while(z--)  
        {  
            scanf("%d%d%d",&n,&w,&h);  
            cnt = start = 0;  
            __h = h*h*1.0/4;  
            for(int i=0;i<n;i++)  
            {  
                scanf("%d%d",&x,&r);  
                if(r*r < __h)  
                {  
                    i--;n--;  
                    continue;  
                }  
                l = sqrt(r*r - __h);  
                A[i].a = x-l > 0 ? x-l : 0;  
                A[i].b = x+l < w ? x+l : w;  
            }  
            sort(A,A+n,cmp);  
            int i,k = -1;  
            while(start < w && A[k+1].a <= start)  
            {  
                float mmax = -1;  
                for(i = k+1;A[i].a <= start && i<n;i++)  
                    if(mmax < A[i].b)  
                    {  
                        mmax = A[i].b;  
                        k = i;  
                    }  
                start = mmax;  
                cnt++;  
            }  
            printf("%d\n",start<w ? 0 : cnt);  
        }  
        return 0;  
    }  
部分参考: http://blog.csdn.net/dgq8211/article/details/7535994


 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值