[AcWing 906] 区间分组

image

差分 + 贪心


点击查看代码
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

int n;

void solve()
{
    cin >> n;
    vector<pair<int,int>> s;
    for (int i = 0; i < n; i ++) {
        int a, b;
        cin >> a >> b;
        s.push_back({a, 1});
        s.push_back({b + 1, -1});
    }
    sort(s.begin(), s.end());
    int res = 0, sum = 0;
    for (auto [x, c] : s) {
        sum += c;
        res = max(res, sum);
    }
    cout << res << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    solve();

    return 0;
}

  1. 利用差分,找到被最多区间覆盖的一段,这段就是所需的最小区间数目

小根堆 + 贪心


点击查看代码
#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;
const int N = 1e5 + 10;
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;
        scanf("%d %d", &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 {
            heap.pop();
            heap.push(r.r);
        }
    }
    cout << heap.size() << endl;
    return 0;
}

  1. 算法思想
    ① 将所有区间按左端点从小到大排序
    ② 从前往后处理每个区间
    判断是否将其放到放到某个现有的组中 $ L[i] \geqslant max(r) $
    如果不存在这样的组,则开新组,然后再将其放进去
    如果存在这样的组,将其放进去,并更新当前组的 $ max(r) $
    (使用小根堆维护右端点最小值,每次只需判断当前区间左端点和小根堆最小值的关系,更新时,把小根堆最小值进行更新)
  2. 算法的最优性解释
    设最优解是 \(ans\) ,一种可行解是 \(cnt\)
    ① 最优解要保证组数最小,即 \(ans \leqslant cnt\)
    ② 根据算法思路,在选第 \(cnt\) 个组时,前 \(cnt - 1\) 个组的区间都与第 \(cnt\) 个组的区间有交集,也就是说,至少需要 \(cnt\) 个组,才能保证区间没有交集,\(ans \geqslant cnt\)
    综上, \(ans = cnt\) ,最优性得证
posted @ 2022-06-04 13:10  wKingYu  阅读(56)  评论(0)    收藏  举报