AcWing
  • 首页
  • 活动
  • 题库
  • 竞赛
  • 应用
  • 更多
    • 题解
    • 分享
    • 商店
    • 问答
    • 吐槽
  • App
  • 登录/注册

AcWing 905. 区间选点(惊奇的发现左右都可)    原题链接    简单

作者: 作者的头像   Accepting ,  2020-03-28 22:18:47 ,  所有人可见 ,  阅读 4590


37


13

鄙人才疏学浅,此中鄙陋甚多,望海涵。

题目描述

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

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

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

输入格式
第一行包含整数N,表示区间数。

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

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

数据范围
1≤N≤105,
−109≤ai≤bi≤109

样例

输入样例:
3
-1 1
2 4
3 5
输出样例:
2

这道题目要求在数轴选点,使每个区间至少包含一个点,本质上是说,相交的区间选一点即可,不相交区间须选二点,其实也就是找到最大不相交区间数量(可参考 Acwing 908)

算法1

按照右端点排序

C++ 代码

#include<iostream>
#include<algorithm>
#include<cstring>

using  namespace std;

const int N=1e5+10;

struct Range
{
    int l,r;
    bool operator< (const Range &W)const
    {
        return r<W.r;
    }
}ranges[N];

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ranges[i]={l,r};
    }
    sort(ranges,ranges+n);
    int res=0,st=-2e9;
    for(int i=0;i<n;i++)
    {
        if(st<ranges[i].l)
        {
            res++;
            st=ranges[i].r;
        }
    }
    cout<< res <<endl;
    return 0;
}

算法2

按照左端点排序

C++ 代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

struct Range
{
    int  l,r;
    bool operator <(const Range &W)const
    {
        return l<W.l;
    }
}range[N];

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        range[i]={l,r};
    }
    sort(range,range+n);
    int res=0,st=-2e9;
    for(int i=0;i<n;i++)
    {
        if(st<range[i].l)
        {
            res++;
            st=range[i].r;
        }
        else
        {
            st=min(st,range[i].r);
        }
    }
    printf("%d\n",res);
    return 0;
}

26 评论


用户头像
土匕   2022-05-13 08:25      2    踩      回复

大家都证明得很牵强,让我也来证明一下,如果有问题,欢迎指出。疑惑点在ans>=cnt,我们可以假设有ans小于cnt,且咋们用算法求出来的区间用数组t表示。那么这个ans肯定要包含咋们算法求出来的区间。那这个ans可不可能有个区间包含了咋们求出来的区间t的两个区间呢。显然不可能,这是算法证明的关键。因为如果有这么一个区间的话,咋们贪心算法肯定能找出来,那么t区间就不是咋们算法求解出来的区间了。所以ans连我们数组t都包含不了,他还想包含全部,简直想屁吃。


用户头像
Dylansisyphe   2022-03-25 11:50      1    踩      回复

感谢大佬,思路很清晰

用户头像
Accepting   2022-03-25 17:55      1    踩      回复

哈哈哈,不点个赞嘛?


用户头像
大头th   2020-11-10 18:34      1    踩      回复

同,第二种方法 为什么取min

用户头像
Accepting   2020-11-10 19:02      1    踩      回复

都是对称操作,但都要掌握,因为有的题只有一个方向可以,如果只记得一种方法虽然熟练但会局限思维!

用户头像
椒盐土豆   2021-12-31 13:11      3    踩      回复

因为你左端点排序的话,一个大区间会存在多个小区间那么要想点数竟可能少,那么就选择小区间的右端点作为覆盖点,小区间可以覆盖大区间,但是不能覆盖大区间内另一个没有重复区域的小区间,所以要维护最右端点值

用户头像
一切皆有解   2022-05-20 18:18    回复了 椒盐土豆 的评论      1    踩      回复

举个例子[3,6],[3,4],[5,6],不取min第二次得到最右端是6,和[5,6]比较满足,res=1,就错了,相当于一个大区间内部可能有多个不相同的小区间,它们并不重复,也需要一个点


用户头像
wangdanhuang   2个月前         踩      回复

优秀


用户头像
ericf   7个月前         踩      回复

贪心好难想【厚里谢】

用户头像
Accepting   7个月前         踩      回复

哈哈哈,确实,不过这题倒是还好,贪心基本思路也就是排序了(顺带一提,这头像有点东西


用户头像
白子伍   2022-01-14 14:05         踩      回复

这道题和有一道区间合并的题,有啥区别吗?我感觉都一样但是代码交上去不对acwing.com/problem/content/805/

用户头像
Accepting   2022-01-14 16:46         踩      回复

得稍微改改,你可以再听y总讲一遍

用户头像
白子伍   2022-01-14 21:34    回复了 Accepting 的评论         踩      回复

okk,好的

用户头像
こんばんは   2022-03-07 20:09         踩      回复

这里你采用类似的方法,求解区间之间的交集,一个交集一个点,就是正确答案,区间合并求得是并集


用户头像
Jsweet   2022-01-13 14:47         踩      回复

想知道重载用在哪儿了,为什么要用重载(c++新手)

用户头像
Accepting   2022-01-14 09:37         踩      回复

重载就是那个struct中operator那一块,重载了小于号,相当于规定了结构体排序的依据

用户头像
Jsweet   2022-01-14 19:03    回复了 Accepting 的评论         踩      回复

那为什么普通的排序不可以哦

用户头像
Accepting   2022-01-14 20:24    回复了 Jsweet 的评论         踩      回复

普通的排序它只能针对比较简单的东西,比如数组,比较复杂的,普通排序是不行的


用户头像
馨意   2021-11-16 21:04         踩      回复

取min应该是缩小公共子区间的范围


用户头像
是晴天呀   2020-11-28 14:50         踩      回复

我看了大佬写的按照左端点的解法,感觉考场上我是想不出来。。我记得当时直播时y总说“按照右端点排列,不要问我为什么啊,就是这么排的”。我感觉两种方法都记的话有点容易混淆,所以感觉如果有小伙伴怕弄不清的话就记住这四道区间题的模板就行,遇到题目时根据题目所属的模板来选择按照左端点还是右端点排序,两种模板(区间选点,最大不相交区间数)按照右端点排序,两种模板(区间覆盖,区间分组)按照左端点排序。

用户头像
Accepting   2020-11-28 18:02         踩      回复

怎么说呢?我觉得只记一个方向不会混淆,因为我是那种模板记得不怎么好的那种,我一般都按左排,特判一些情况,其实特判也比较简单。

用户头像
椒盐土豆   2021-12-31 13:13         踩      回复

感觉更多想出来的左端点排序,因为右端点排序要么要写重载操作符要么写仿函数,如果第一次做应该想的都是左排端点序


用户头像
xswlhahaha   2020-10-29 21:39         踩      回复

第二种算法,为什么else中是取min呢?

用户头像
大头th   2020-11-10 18:45         踩      回复

明白了 大浪数据有可能中间出现 [1,9], [2,3], [4,6] 这种情况,


用户头像
Aranne   2020-07-21 23:34         踩      回复

左端点排序的话,从右往左扫也可以

用户头像
Accepting   2020-07-22 09:09         踩      回复

嗯嗯,是对称的!


你确定删除吗?

© 2018-2023 AcWing 版权所有  |  京ICP备17053197号-1
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息