算法学习之每日一题Day2

题目      区间选点

一、有关题目(涉及算法:贪心)

1.题目来源:Acwing 905 

2.题目链接: https://www.acwing.com/problem/content/907/

3.题目描述:

给定 N 个闭区间 [ai,bi]

,请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

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

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

输入格式

第一行包含整数 N

,表示区间数。

接下来 N

行,每行包含两个整数 ai,bi

,表示一个区间的两个端点。

输出格式

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

数据范围

1≤N≤105,
−109≤ai≤bi≤109

输入样例:

3
-1 1
2 4
3 5

输出样例:

2

 二、算法思路

1.思路

(1)将所有区间按照右端点的值,按照从小到大的顺序排列。

(2)从前到后处理每个区间。

   如果,当前区间中已经包含点,则直接pass。

   否则,选择当前区间的右端点。

2.对思路的解释

(1)本题目的样例具有局限性,将样例所示区间按照左端点或者右端点进行排序效果相同。

若有下面两个区间,便可易得应该按照右端点的值从小到大排序

(2)由于排序方式的原因,选取的点位于右端点可以尽可能覆盖更多的点。

(3)在没有严谨证明的情况下,我们可能会不确定选择区间中的哪个点,因此可能会想到选择区间中的任意一点。

起初,我的初版思路就是这样。

排序方式为,先将区间按长短,从小到大进行排序。

选点方式为,取任意点。

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5+10;

struct interval{
    int l;
    int r;
    int length;
}it[N];

int visited[N];
int t;
int i, j;

bool cmp(interval x, interval y){
    return  x.length < y.length;
}

int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++ i){
        scanf("%d%d", &it[i].l, &it[i].r);
        it[i].length = it[i].r-it[i].l;
    }
    
    sort(it, it+n, cmp);
    
    for(int i = 0; i < n; ++ i){
        if(visited[i]) continue;
        ++ t;
        visited[i] = 1;
        for(int j = i+1; j < n; ++ j){
            if(visited[j]) continue;
            if((it[i].l>=it[j].l && it[i].l <= it[j].r) || (it[i].r>=it[j].l && it[i].r <= it[j].r)) visited[j] = 1;
        }
    }
    
    printf("%d", t);
}

这中思路是有弊端的,在某些情况下会导致选点过少。因此11个测试样例,只通过了6个。

三、代码实现

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5+10;

struct interval{
    int l;
    int r;
}it[N];

int t, p;

bool cmp(interval x, interval y){
    return x.r < y.r;
}

int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++ i){
        scanf("%d%d", &it[i].l, &it[i].r);
    }
    
    sort(it, it+n, cmp);
    
    p = it[0].r;
    ++ t;
    for(int i = 1; i < n; ++ i){
        if(p >= it[i].l && p <= it[i].r) continue;
        p = it[i].r;
        ++ t;
    }
    
    printf("%d", t);
    return 0;
}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值