1. 区间选点
1.1 题目大意
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
input
第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)
output
一个整数,代表选点的数目
1.2 贪心策略
为了用尽量少的点,需要让一个点在更多的区间之中,有两个方法,
- 先满足终点(右端点)小的区间,如:满足了[0,s]区间内有点,则可满足(0,2s)区间内有点,反之,不可
- 先满足长度比较小的区间,因为满足满足长度小的区间,则可满足与之有交集或包含它的长度长的区间,反之,则不一定。如:满足了[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;
}