区间问题及模板

本文介绍了区间问题的五个子任务:区间合并通过合并相交区间减少数量;区间选点最小化覆盖所需点的数量;最大不相交区间数量寻找最少选取点覆盖所有区间;区间分组划分无交集组数最少的方案;区间覆盖同样关注最小组数。通过实例和代码展示了如何解决这些技术挑战。
摘要由CSDN通过智能技术生成

1、区间合并

Acwing803. 区间合并
给定 n n n 个区间 [ l i , r i ] [l_i,r_i] [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如: [ 1 , 3 ] [1,3] [1,3] [ 2 , 6 ] [2,6] [2,6] 可以合并为一个区间 [ 1 , 6 ] [1,6] [1,6]

输入格式
第一行包含整数 n n n

接下来 n n n 行,每行包含两个整数 l l l r r r

输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围
1 ≤ n ≤ 100000 1\leq n\leq100000 1n100000,
− 1 0 9 ≤ l i ≤ r i ≤ 1 0 9 −10^9\leq l_i\leq r_i\leq10^9 109liri109
输入样例:

5
1 2
2 4
5 6
7 8
7 9

输出样例:

3
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
int n;
vector<PII> nums,res;
int main()
{
    scanf("%d", &n);
    for(int i = 0 ;i < n ;i ++){
        int a,b;
        scanf("%d%d", &a, &b);
        nums.push_back({a,b});
    }
    sort(nums.begin(),nums.end());
    for(int i =0 ,j =1 ; i < n ; ){
        int r = nums[i].y;
        while(j <n && nums[j].x<=r){
            r = max(r,nums[j].y);
            j++;
        }
        res.push_back({nums[i].x,r});
        i = j ;
        j++;
    }
    // for(auto a:res){
    //     printf("%d %d \n",a.x,a.y);
    // }
    printf("%d",res.size());
    return 0;
}

2、区间选点

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

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

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

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

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

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

数据范围
1 ≤ N ≤ 1 0 5 1\leq N\leq10^5 1N105,
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 −10^9\leq a_i\leq b_i\leq 10^9 109aibi109
输入样例:

3
-1 1
2 4
3 5

输出样例:

2
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+10;

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

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

参考题解

3、最大不相交区间数量

AcWing 908. 最大不相交区间数量
给定 N N N 个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

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

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

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

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

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

数据范围
1 ≤ N ≤ 1 0 5 1\leq N\leq10^5 1N105,
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 −10^9\leq a_i\leq b_i\leq 10^9 109aibi109
输入样例:

3
-1 1
2 4
3 5

加粗样式

2

参考代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

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

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d%d", &range[i].l, &range[i].r);

    sort(range, range + n);

    int res = 0, ed = -2e9;
    for (int i = 0; i < n; i ++ )
        if (ed < range[i].l)
        {
            res ++ ;
            ed = range[i].r;
        }

    printf("%d\n", res);

    return 0;
}

4、区间分组

Acwing906. 区间分组
给定 N N N 个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。

输出最小组数。

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

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

输出格式
输出一个整数,表示最小组数。

数据范围
1 ≤ N ≤ 1 0 5 1\leq N\leq10^5 1N105,
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 −10^9\leq a_i\leq b_i\leq10^9 109aibi109
输入样例:

3
-1 1
2 4
3 5

输出样例:

2
#include<bits/stdc++.h>
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 n;
int main()
{
    scanf("%d", &n);
    for(int i = 0 ;i < n ;i ++){
        int x,y;
        scanf("%d%d", &x, &y);
        range[i] = {x,y};
    }
    priority_queue<int,vector<int>,greater<int> > heap;
    sort(range,range+n);
    for(int i = 0 ;i < n ;i ++){
        if(heap.empty() || heap.top() >= range[i].l) heap.push(range[i].r);
        else{
            heap.pop();
            heap.push(range[i].r);
        }
    }
    printf("%d\n",heap.size());
    
    return 0;
}

5、区间覆盖

给定 N N N 个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。

输出最小组数。

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

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

输出格式
输出一个整数,表示最小组数。

数据范围
1 ≤ N ≤ 1 0 5 1\leq N\leq10^5 1N105,
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 −10^9\leq a_i\leq b_i\leq10^9 109aibi109
输入样例:

1 5
3
-1 3
2 4
3 5

输出样例:

2

参考代码

#include<bits/stdc++.h>
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 n;
int main(){
    int st ,ed;
    scanf("%d%d", &st, &ed);
    scanf("%d", &n);
    for(int i = 0 ;i < n; i ++){
        int x,y ;
        scanf("%d%d", &x, &y);
        range[i] = {x,y};
    }
    
    sort(range,range+n);
    bool flag = false;
    int res = 0 ;
    for(int i = 0 ;i < n; i++){
        int j = i , r = -2e9;
        while(j < n && range[j].l<=st){
            r = max(r,range[j].r);
            j++;
        }
        if(r < st){
            res = - 1;
            break;
        }
        res ++ ;
        if(r>=ed){
            flag = true;
            break;
        }
        st = r;
        i = j -1;
    }
    printf("%d",flag?res:-1);
    return 0;
    
}

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值