算法学习笔记(51)——区间问题

区间问题

区间选点

题目链接:AcWing 905. 区间选点

题目描述

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

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

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

输入格式

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

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

输出格式

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

数据范围

\(1 \le N \le 10^5,\)

\(−10^9 \le a_i \le b_i \le 10^9\)

输入样例

3
-1 1
2 4
3 5

输出样例

2

算法思路

img

  1. 将每个区间按照右端点从小到大排序
  2. 从前往后依次枚举每一个区间
    • 如果当前区间已经包含点,则直接pass
    • 否则选择当前区间的右端点
#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()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    int res = 0, ed = -2e9;
    for (int i = 0; i < n; i ++ )
        if (range[i].l > ed) {
            res ++;
            ed = range[i].r;
        }
     cout << res << endl;
     
     return 0;
}

最大不相交区间数量

题目链接:AcWing 908. 最大不相交区间数量

题目描述

给定 \(N\) 个闭区间 \([a_i,b_i]\),请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

输入格式

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

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

输出格式

输出一个整数,表示可选取区间的最大数量。

数据范围

\(1 \le N \le 105,\)

\(−10^9 \le a_i \le b_i \le 10^9\)

输入样例

3
-1 1
2 4
3 5

输出样例

2

与上一题思路及代码完全相同。


区间分组

题目链接:AcWing 906. 区间分组

题目描述

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

输出最小组数。

输入格式

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

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

输出格式

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

数据范围

\(1 \le N \le 105,\)

\(−10^9 \le a_i \le b_i \le 10^9\)

输入样例

3
-1 1
2 4
3 5

输出样例

2

算法思路

  1. 将所有区间按左端点从小到大排序
  2. 从前往后处理每个区间
    • 判断能否将其放到某个现有的组中(判断当前区间的左端点是否小于某个现有的组的右端点)
      • 如果不存在这样的组,则开新组,然后再将其放进去
      • 如果存在这样的组,将其放进去,并更新当前组的Max_r

可以利用小根堆来动态维护最小的Max_r

#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 100010;

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

int main()
{
    cin >> n;
    for (int i = 0 ; i < n; i ++ ) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    priority_queue<int, vector<int>, greater<int>> heap;
    for (int i = 0; i < n; i ++ ) {
        auto r = range[i];
        if (heap.empty() || heap.top() >= r.l) heap.push(r.r);
        else {
            int t = heap.top();
            heap.pop();
            heap.push(r.r);
        }
    }
    
    cout << heap.size() << endl;
    
    return 0;
}

区间覆盖

题目链接:AcWing 907. 区间覆盖

题目描述

给定 \(N\) 个闭区间 \([a_i,b_i]\) 以及一个线段区间 \([s,t]\),请你选择尽量少的区间,将指定线段区间完全覆盖。

输出最少区间数,如果无法完全覆盖则输出 \(−1\)

输入格式

第一行包含两个整数 \(s\)\(t\),表示给定线段区间的两个端点。

第二行包含整数 \(N\),表示给定区间数。

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

输出格式

输出一个整数,表示所需最少区间数。

如果无解,则输出 \(−1\)

数据范围

\(1 \le N \le 10^5,\)

\(−10^9 \le a_i \le b_i \le 10^9,\)

\(−10^9 \le s \le t \le 10^9\)

输入样例

1 5
3
-1 3
2 4
3 5

输出样例

2

算法思路

img

  1. 将所有区间按照左端点从小到大排序
  2. 从前往后依次枚举每个区间,在所有能覆盖start的区间中,选择右端点最大的区间,然后将start更新成右端点的最大值
#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 l < w.l;
    }
}range[N];

int main()
{
    int st, ed;
    cin >> st >> ed;
    cin >> n;
    for (int i = 0; i < n; i ++ ) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    int res = 0;
    bool success = false;
    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) {
            success = true;
            break;
        }
        
        st = r;
        i = j - 1;
    }
    
    if (!success) res = -1;
    cout << res << endl;
    
    return 0;
}
posted @ 2023-01-11 17:35  S!no  阅读(179)  评论(0编辑  收藏  举报