区间覆盖

题目:区间覆盖
题意:数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1

输入:
第一行:N和T
第二行至N+1行: 每一行一个闭区间。

输出:
选择的区间的数目,不可能办到输出-1

解题思路:区间覆盖问题,贪心求解;先去头去尾,也就是线段左端点小于1的让他变成1(如果右端点也小于1,并不影响);之后按照线段左端点升序排序。然后每次取右端点最大的(如果左端点相同的话),如果左端点不同,进行一次特判,看下一个点是不是在这个值的左边+1(必须加1,上面有提示),如果在的话,就停止输出-1;不在的话,把要覆盖的线段的左端点变成你当前选的那个线段的右端点,然后继续截断头,直到求出结果为止;
那么这个方法为什么可以呢?我们以覆盖的最左边的那个线段为例,我们选的是左端点小于等于1的线段中右端点的值减去1最大的那个;如果不选这个,那我们只能选比这个更小的,这样你剩下的区间就会变多,你的情况没有变好甚至变坏;同样你选完最左边的之后继续选线段面临的还是这个问题。从这里可以看出我们的贪心应该是最优的。

相似的题目(万恶的奶牛)

坑人之处:请注意上面所说的整点覆盖,本人做的时候还没有这个信息,便以为是线段覆盖,然后疯狂的白给。。。所以一定要加一!

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
bool cmp(pair<int,int> a,pair<int,int> b)
{
    return a.first<b.first;
}
int main()
{
    int n,t,x,y;
    vector<pair<int,int> > h;
    while(scanf("%d%d",&n,&t)!=EOF)
    {
        int total=1,flag=-1,b=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            if(x>y)//由于被坑的有点厉害,就谨慎了一点
            {
                swap(x,y);
            }
            if(x<1){x=1;}//裁剪
            if(y>t){y=t;}
            h.push_back(make_pair(x,y));
        }
        if(n==0||t<1)//谨慎
        {
            printf("-1\n");
            h.clear();
            continue;
        }
        sort(h.begin(),h.end(),cmp);//排序
        if(h[0].first>1)//特判第一个
        {
            printf("-1\n");
            h.clear();
            continue;
        }
        for(int i=0;i<n;i++)//进行贪心
        {
            if(h[i].first>b)//如果当前线段左端点数值和b不同,说明左端点为b的线段已经筛选完了
            {
                if(h[i].first>flag+1)//记住,一定要加个1!!!
                {
                    printf("-1\n");
                    break;
                }
                total++;//所选的线段数加1
                for(int j=i;j<n;j++)//把左端点进行变更,并进行裁剪
                {
                    if(h[j].first<flag+1)
                    {
                        h[j].first=flag+1;
                    }else
                    {
                        break;
                    }
                }
                b=flag+1;//变更左端点
            }
            flag=max(flag,h[i].second);//求个右端点最大的
            if(flag==t)//判断一下
            {
                printf("%d\n",total);
                break;
            }
            if(i==n-1)//扫完了还没成功,就说明失败了
            {
                printf("-1\n");
            }
        }
        h.clear();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值