[贪心]Exercise Week3 C-区间覆盖

题意

数轴上有 n个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]
PS:覆盖整点,如果做不到 则输出-1

样例

样例输入:
第一行:N和T (1<=n<=25000) ( 1<=t<=1,000,000)
第二行至N+1行: 每一行一个闭区间。
3 10
1 7
3 6
6 10
样例输出:
选择的区间的数目,不可能办到输出-1
2


思路

看到题目让求最优解,则我们首先能想到的就是贪心

因为要求用尽量少的区间,又需要完全覆盖,故我们初步的想法是将区间按左端点升序排列,而且我们想让区间尽可能的发挥它的作用,所以当左端点相同时,我们优先选用更长的区间

当然 由于覆盖的是[1,t] 所以我们可以在输入时对初始的区间进行切割,如果左端点<1就置为1 如果右端点>t就置为t

首先 如果我们排完序后 第一个区间的的左端点不是1 就可以直接判断无法覆盖 输出"-1"

然后我们开始选择区间。maxl变量初值设为p[1].r,用来表示几个左端点都在当前起点左边的区间 它们右端点的最大值(因为我们要取它们中最长的一个) 。如果当前区间的左端点在起点的右侧,说明之后已经没有左端点在起点左边的区间了,因此我们取右端点最大的区间,令ans++ 并且将起点更新为 maxl+1,此时我们判断当前区间的p[i].l<=s? 如果是则将maxl设为p[i].r,作为maxl新的初值,如果不满足条件则说明区间中间会有一小段不可能被覆盖到 因此我们直接结束掉

什么时候程序结束呢?如果在某次区间选择的最后,maxl已经==t了(因为我们将所有区间的右端点都限制在了t 故可以用相等判断) 那么说明已经完全覆盖了 我们就可以输出ans,值得注意的是 最后一个区间我们虽然选了,但是没有进行ans++,因此我们要把ans初值设为1 或者初值为0,输出ans+1

如果循环结束,程序还没有执行完,说明最后一小段没有被覆盖到,我们依旧输出"-1"


总结

1.贪心的大体思路我们可能能想到,但是具体的一些细节还是挺令人抓狂的,这需要我们长期的积累
2.exit(0) 还挺好用的 之前没用过(orz)


代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
struct node
{
    int l,r;
    bool operator < (const node &x) const{
        if(l!=x.l)  return l<x.l;
        else return r>x.r;
    }
} p[25100];
int main()
{
    
    int n,t,a,b,s=1,ans=1;
    cin>>n>>t;
    for(int i=1;i<=n;i++)   
    {
        scanf("%d%d",&a,&b);
        a<1? p[i].l=1:p[i].l=a;
        b>t? p[i].r=t:p[i].r=b;
    }
    sort(p+1,p+n+1);
    int maxl=p[1].r;
    if(p[1].l!=1)   {cout<<"-1"<<endl;}
    else
    {
        for(int i=1;i<=n;i++)
        {
            if(p[i].l<=s) maxl=max(maxl,p[i].r);//若有多个包含当前起点的区间 选择最大的那个
            else
            {
                ans++;
                s=maxl+1;//更新起点
                if(p[i].l<=s)   maxl=p[i].r;//设初值
                else {cout<<"-1"<<endl; exit(0);}  //无法完全覆盖
            }
            if(maxl==t) {cout<<ans<<endl; exit(0);}  
        }
        cout<<"-1"<<endl;
    }  

    return 0;
}

发布了12 篇原创文章 · 获赞 0 · 访问量 516

猜你喜欢

转载自blog.csdn.net/linshen_jianhai/article/details/104705267