贪心1

1. 区间选点

1.1 题目大意

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

第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)

output

一个整数,代表选点的数目

1.2 贪心策略

为了用尽量少的点,需要让一个点在更多的区间之中,有两个方法,

  1. 先满足终点(右端点)小的区间,如:满足了[0,s]区间内有点,则可满足(0,2s)区间内有点,反之,不可
  2. 先满足长度比较小的区间,因为满足满足长度小的区间,则可满足与之有交集或包含它的长度长的区间,反之,则不一定。如:满足了[1,s]区间内有点,则可满足[1,2s]区间内有点,反之,不可

综合以上两条,贪心策略就是:使用那些终点小的(第一关键词),长度短的(第二关键词)的终点做为选择的点。(如不是终点:选择c ∈ \in [a,b] ,则(c,b]区间没有点)

1.3 求解与代码

求解时,依据贪心策略,用sort对区间进行排序,之后依次选择每一个区间,若这个区间内不含点,则选择右端点,并记录最后一个选择的点的位置,以便后续区间判断。

#include<bits/stdc++.h>
using namespace std;
struct Point{
 int x,y;
 Point(){}
 Point(int _x, int _y){
  x=_x; y=_y;
 }
 bool operator<(const Point & p) const
 {  //尽量靠前的,且长度尽量少的 
  return y==p.y? x>p.x:y<p.y; 
 }
};
int main()
{
 int n;
 Point p[200];
// freopen("in.txt","r",stdin);
 scanf("%d",&n);
 for(int i=0;i<n;i++)
 {
  scanf("%d%d",&(p[i].x), &(p[i].y)); 
 }
 sort(p,p+n);
 int cnt=1; int pos=p[0].y; // 贪心:先满足结束早的,长度短的 
 for(int i=1;i<n;i++)
 {
  if(pos>=p[i].x&&pos<=p[i].y)
  continue;
  else if(pos<p[i].x) {
   cnt++;
   pos=p[i].y;
  }
     //不存在 pos > p[i].y  
 }
 printf("%d\n",cnt);
 return 0; 
}

2. 区间覆盖

2.1 题目大意

选择尽量少的,给定的区间,使之覆盖[1,T]这一区间上的整点
input

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

output

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

2.2 贪心策略

首先要使用必须能够覆盖目标点,且长度尽量长的区间。若从左到右考察每一个整点,则要选择左端点尽量小的点,这是因为:所有的整点都要被覆盖,若根据所有区间的左端点,发现存在整点无法被覆盖,则可及时终止。长度长是为了覆盖更多的整点。

除此之外,长度尽量长并不是一开始就确定的,是基于当前需要覆盖的区间
( b i , T ] , 1 < b i < T (b_i,T], 1<b_i<T bi,T],1<bi<T 与每个区间之间的交集决定的。每次选择一个区间之后,就要根据右端点 b i b_i bi,截取原区间,得出剩余待覆盖的区间,以此为基础,再去选择下一个含有 b i + 1 b_i+1 bi+1且覆盖最多。

2.3 求解与代码

左端点尽量小可以用sort在初始化的时候完成,而长度尽量长的选择,在sort中可以加入第二关键词排序,但就算加了,之后的每一步还是要去寻找,包含 b i b_i bi,且长度尽量长的区间,意义不是太大。

寻找过程:

next = i+1 //i+1是待覆盖区间左端点
for(int k=index+1;k<n;k++) // 要对剩余的区间中搜寻,找那些开始晚,但是结束晚的 
 {
      if(i+1<p[k].x) //因为p数组以x为第一关键字,此时已经没有包含i+1的区间了 
         break;               
    else if(p[k].y>=next &&next>=p[k].x) //有交集,且j没有完全覆盖k 
    {
     if((p[k].y-i)>max)  // max就是当前最长区间长度
      {
         flag=1;
         max= p[k].y-i;
         next=p[k].y; 
         index=k; 
      }
     }
  } 
   if(flag) //找到了下一个区间 
    {
          i=next;
          cnt++;
          max=0;
          flag=0;
    }

代码

#include<iostream>
#include<algorithm>
using namespace std;
struct Par
{
 int x,y;
 Par(){ }
 Par(int _a,int _b){
  x=_a;
  y=_b;
 }
 bool operator< (const Par& p) const{
   return x==p.x?y>p.y:x<p.x; 
 }
} ;
int main()
{
    int n;
 int t;
 freopen("in.txt","r",stdin);
 scanf("%d%d",&n,&t);
 Par p[30000];
 int x,y; 
 for(int i=0;i<n;i++)
 {
   scanf("%d%d",&p[i].x,&p[i].y); 
   if(p[i].x<=0&&p[i].y>=1) p[i].x=1;
 }
 sort(p,p+n);
 int  cnt=0;
 int i; 
 int flag=0; 
 int max=0;
 int index=-1; //当前的j 
 for(i=0;i<t; ) //i是需要被覆盖的整点 
 {
   int next= i+1; 
         for(int k=index+1;k<n;k++) // 要对剩余的区间中搜寻,找那些开始晚,但是结束晚的 
   {
                if(i+1<p[k].x) //因为p数组堆以x为第一关键字,此时已经没有包含i+1的区间了 
    {
     break;                 
                }
                else if(p[k].y>=next &&next>=p[k].x) //有交集,且j没有完全覆盖k ,深究<= or < 
    {
     if((p[k].y-i)>max) 
        {
         flag=1;
         max= p[k].y-i;
         next=p[k].y; 
      index=k; 
       }
                }
   } 
        if(flag) //找到了下一个区间 
     {
          i=next;
          cnt++;
          max=0;
          flag=0;
        }
         else  break;  
 }
 if(i<t) printf("%d\n",-1);
 else printf("%d\n",cnt);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值