week3 C - 区间覆盖

题意:

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

输入

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


思路:

运用贪心策略求解,贪心的准则是:选择一条可以覆盖到线段的并且长度最大的区间。将区间按照左端点left升序排序,如果left相同则按照right排序,初始化时设置一个rightlength,来标记初始区间的右端点,设置一个maxlength来标记新的区间的右端点到rightlength的最大距离,遍历排序好的区间数组,新的区间无非两种情况:
1、左端点leftrightlength之前,表示新的区间与被选入的区间有交集 ,选择出有交集的区间最长的一条
2、左端点leftrightlength之后,表示新的区间与被选入的区间没有交集,覆盖失败
对于有交集的区间,这时计算它的右端点rightrightlength的长度是否大于maxlength,如果大于则证明找到了一个可以延伸的区间,更新最大长度maxlength,当把与被选入的区间有交集的新区间全部遍历完毕时,就可以选择出长度最大的区间temp,最后rightlength更新为新的右端点。


总结:

这个问题犯错在,当一个新的区间的左端点在标记的右端点之前,表示有交集时,少考虑了区间包含的情况,比如(1,9) (2,3),导致判断为没有覆盖到,输出了-1。
运用贪心策略时,需要找好贪心的指标,选择出一个最优的解决方案,用最优的方案求出解,而这个求最优的解决方案需要多次考虑,判断出区间的各种情况:有交集、无交集,并且在有交集的区间中选择最长的。


代码:

  #include <stdio.h>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;

struct qvjian
{
 int left;
 int right;
 qvjian(int _l,int _r)
 {
     left = _l;
     right = _r;
 }
 qvjian() {}

 inline bool friend operator<(const qvjian &a,const qvjian &b)
 {
     if (a.left != b.left)
     {
         return a.left < b.left;
     }
     else
     {
         return a.right < b.right;
     }
     
 }
}test[25000];

int main()
{
 int N,T;
 int size = 0;
 scanf("%d%d",&N,&T);
 for (int i = 0; i < N; i++)//预处理 先去除掉完全不符合的区间
 {
     int l,r;
     scanf("%d%d",&l,&r);
     if (l >=1 && l <= T)
     {
         test[i].left = l;
         test[i].right = r;
         size++;
     }
 } 
 sort(test,test+size);
 if (test[0].left != 1)
 {
     printf("-1");
 }
 else
 {
     int ans = 1;
     int rightlength = test[0].right;
     int temp = 0;
     int maxlength = 0;
     int find = 0;
     for (int i = 1; i < size; i++)
     {
         find = 0;             
         if (rightlength >= T)
         {
             break;
         }
         while (i < size && test[i].left <= rightlength + 1)
         { //当区间的左端点没超过 设置的右端点时,判断长度  
             if (maxlength < (test[i].right - rightlength))
             {//该点到rightlength的距离超过了最大距离 更新
                 maxlength = test[i].right - rightlength;
                 temp = i;//记录下最大距离的点
                 find = 1;
                 i++;
             }
             else//没找到的情况 包含
             {
                 find = 1;
                 i++;
             }
         }
         if (find == 1)//如果找到了可以覆盖的最长的边 更新右端点
         { 
             rightlength = test[temp].right;
             maxlength = 0;
             ans++;
             i--;
         }
         if (find == 0)
         {
             break;
         }
     }
     if (rightlength < T)//已经找完所有的边 未能覆盖 或者 中间出现了断层
         printf("-1");
     else
         printf("%d",ans);
 }
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值