acwing905 区间选取笔记

acwing905 区间选点
题目描述

给定 N 个闭区间 [$a_i,b_i$],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

输出选择的点的最小数量。

位于区间端点上的点也算作区间内。

输入格式

第一行包含整数 N,表示区间数。

接下来 N 行,每行包含两个整数 $a_i,b_i$,表示一个区间的两个端点。

输出格式

输出一个整数,表示所需的点的最小数量。

输入输出样例 #1
输入 #1
3
-1 1
2 4
3 5
输出 #1
2
说明/提示

$ 1≤N≤10^5 $,
$ −109≤a_i≤b_i≤109 $


思路(上述类型一)

1.我们不妨将所有区间按照右端点从小到大排序

2.我们从第一个区间开始,取第一个区间的右端点,排除掉所有右端点覆盖的区间,继续取排除后的所有区间中,第一个区间的右端点。

证明

直接证明:设选取的点集为cnt,最优解点集为ans,不妨证明cnt<=ans &&cnt>=ans,由集合知识得cnt==ans

首先,对于每个区间,它要么给出右端点,要么被别人的右端点覆盖,所以cnt显然能覆盖所有区间,所以cnt>=ans

其次,我们考虑所有被选取右端点的这cnt个区间,这些区间首位不相连,因此至少需要cnt个区间去覆盖他们,所以cnt<=ans

故cnt==ans,即cnt是贪心最优解

或者用交换论证:

假设对于k个区间,我们已经选择了最优解,在选择第k+1个区间的时候,我们选择最右边的贪心策略不会比其他策略差,推断最优解

代码
#include<algorithm>
#include<iostream>
const int N=100010;
struct coor{
    int l,r;
    coor(){
        l=0,r=0;
    }
    bool operator<(const coor&coor_1)const{
        if(r==coor_1.r)return l<coor_1.l;
        return r<coor_1.r;
    }
}e[N];
int main(){
    int n;
    std::cin>>n;
    for(int i=0;i<n;i++){
        int l,r;
        std::cin>>l>>r;
        e[i].l=l,e[i].r=r;
    }
    std::sort(e,e+n);
    int cnt=0,last_p=-2e9;//-2e9代表非常小
    //我们右区间是严格递增的,所以选择了一个右端点之后
    //只需要看接下来点的左端点是否覆盖即可
    //其实没必要枚举接下来所有点的左端点,因为该左端点能被last_p覆盖
    //那么last_p更新会变大,也能覆盖
    //所以算法:枚举右端点作为p,找到第一个没覆盖的点,更新其右端点为p
    for(int i=0;i<n;i++){
        if(e[i].l>last_p){
            cnt++;
            last_p=e[i].r;
        }
    }
    std::cout<<cnt<<std::endl;
}

知识清单

1.operator:重载运算符,重新定义我们coor结构体的<等运算符

重载运算符的模板大致可分为下面俩部分。

/*类定义内重载*/ 返回类型 operator符号(参数){...} /*

类定义内声明,在外部定义*/ 返回类型 类名称::operator符号(参数){...}

我们这里是返回一个bool,当前类的r小于传入(比较类)的时候,返回1(我们知道整数a<b也是返回0/1)

这样定义以后我们能执行bool q=e[0]<e[i] (编译层面相当于bool q=e[0].operator<(e[1]);)

2.两个const?

第一个 const—— 形参 const Vector& other,表示传入的参数在函数体内不会被修改,且能允许函数接受 常量对象 作为参数。

第二个 const —— 成员函数末尾的 const,这个const修饰的是整个成员函数, 表示该成员函数不会修改调用它的对象(即 this 所指的对象)。

两个const实际上表示左右操作数不被修改,即a+b,ab不变。

3.sort怎么用的operator?

关于sort有两种主要形式

// 形式1:默认使用 operator<
template<class RandomIt>
void sort(RandomIt first, RandomIt last);

// 形式2:使用自定义比较函数
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);

调用sort(v.begin(), v.end());编译器会自动匹配 第一种形式,在这里会去结构体里面找operator<,没有的话报错(sort默认是<)

也可以调用第二种形式,主要是lambda表达式和自定义函数

自定义调用第二种形式

bool cmp(const Point &a, const Point &b) {
    if (a.x != b.x) return a.x < b.x;
    return a.y > b.y; 
}

int main() {
    vector<Point> v = {{2,3},{1,5},{2,1},{1,2}};
    sort(v.begin(), v.end(), cmp);
}

lambda调用第二种

sort(v.begin(), v.end(), [](const Point &a, const Point &b){
    if (a.x != b.x) return a.x < b.x;
    return a.y < b.y;
});
posted @ 2025-10-18 12:39  hardestnut  阅读(9)  评论(0)    收藏  举报