C++ 贪心问题、区间分组(含问题分析与代码)

题目 AcWing906.区间分组

原题链接

描述

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

输出最小组数。

输入

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

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

输出

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

数据范围

1 ≤ N ≤ 1 0 5 1≤N≤10^{5} 1N105
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 −10^{9}≤ai≤bi≤10^{9} 109aibi109

样例输入

3
-1 1
2 4
3 5

样例输出

2

思路

这道题用到一个很重要的数据结构priority_queue,需要包含头文件<queue>。优先队列具有队列的所有特性,包括队列的基本操作,只是在这基础上添加了内部的一个排序,它本质是一个实现的。

优先权队列有以下基本操作:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容

定义:priority_queue<Type, Container, Functional> heap;

Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。一般定义方式为:

1 //升序队列,小顶堆
2 priority_queue <int, vector<int>, greater<int>> heap;
3 //降序队列,大顶堆
4 priority_queue <int, vector<int>, less<int>> heap;

本道题的贪心准则:按照区间左端点从小到大排序。

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

核心代码分析

我们按左端点从小到大遍历,再将每个区间的左端点 range[i].l与每一组的最右端点的最小值 heap.top()比较:
heap.top() >= range[i].lheap为空,则说明没有一组集合可以包含该区间,因此建立新的分组 heap.push(range[i].r)
heap.top() < range[i].l,说明有分组可以包含该区间,我们默认把该区间加入到第一个分组中(第一个分组的右端点值较小,这样可以使每个分组包含尽量多的区间),然后从 heap中弹出第一个分组的右端点值,并用 range[i].r更新第一个分组的右端点。

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;
struct Range
{
    int l, r;
    bool operator<(const Range& R)const
    {
        return l < R.l;
    }
}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;
    //定义小根堆,用来存放每一组区间的最右端点
    priority_queue<int, vector<int>, greater<int>> heap;
    for (int i = 0; i < n; i++)
    {
        if (heap.empty() || heap.top() >= range[i].l)
        {
            res++;//建立新的分组
            heap.push(range[i].r);
        }
        else
        {
            //弹出第一组右端点的值并更新
            heap.pop();
            heap.push(range[i].r);
        }
    }
    printf("%d", res);
    return 0;
}

欢迎交流与指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值