zoukankan      html  css  js  c++  java
  • AcWing 906. 区间分组

    题目传送门

    一、读懂题目

    (n)个区间(a[i])~(b[i]),将这些区间进行分组操作,要求每组内部的区间不能存在交集(有一个点共享也不行!),求最小组数。

    注意一点,只要组内所有的区间不存在交集就可以算是一个组,详情看下图:

    你看,这道题很神奇吧,别看有那么多的区间,其实按照题目要求进行分组,最后分的组可能不是你想象的那样。

    二、实现思路

    1. 使用小顶堆记录已经创建的组,组的值用它最后一个成员的右边界表示:x.r

    2. (heap.top()) 表示已有组的最小右边界,这就意味着,其它组的右边界肯定比这个值要大,如果遍历到的区间左端点小于等于最小的右边界(就是有交叉的意思),再加上现在是按左端点排的序,意味着比它左边小的都已经入了小顶堆,它和最小的有冲突,必须也和其它的有冲突,直接创建新组!

    3. 不冲突的话,加入到当前组中!默认把该区间加入到右边界最小的分组中,方法:取出这个分组的右边界,并用 (range[i].r) 更新这一分组的右边界。

    三、实现代码

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 100010;
    int n;
    
    //用一个小顶堆来存储到底有多少个组,小顶堆记录的是组的最后端点位置
    priority_queue<int, vector<int>, greater<int>> heap;
    
    struct Range {
        int l, r;
    } range[N];
    
    //强制要求使用这种结构体的排序自定义函数方式
    //按每个区间的左端点从小到大排序
    bool cmp(const Range &a, const Range &b) {
        return a.l < b.l;
    }
    
    int main() {
        //优化输入
        ios::sync_with_stdio(false);
        cin >> n;
        for (int i = 0; i < n; i++) {
            int l, r;
            cin >> l >> r;
            range[i] = {l, r};
        }
        sort(range, range + n);
    
        //遍历每个区间
        for (int i = 0; i < n; i++) {
            auto x = range[i];
            //空的,或者有交集(冲突)开辟新的组
            if (heap.empty() || heap.top() >= x.l) heap.push(x.r);
            else {
                //合并到旧的组
                heap.pop();
                heap.push(x.r);
            }
        }
        //结果是一共有多少个组
        printf("%d
    ", heap.size());
        return 0;
    }
    

    四、另类思路

    看了一下,貌似是求最大区间厚度的问题。可以把这个问题想象成活动安排问题。

    有若干个活动,第(i)个活动开始时间和结束时间是([S_i,F_i]),同一个教室安排的活动之间不能交叠,求要安排所有活动,少需要几个教室?

    有时间冲突的活动不能安排在同一间教室,与该问题的限制条件相同,即最小需要的教室个数即为该题答案。

    我们可以把所有开始时间和结束时间排序,遇到开始时间就把需要的教室加(1),遇到结束时间就把需要的教室减(1),在一系列需要的教室个数变化的过程中,峰值就是多同时进行的活动数,也是我们至少需要的教室数。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 100100;
    
    int b[2 * N];   //key,value:第几个端点,坐标值
    int idx;        //用于维护数组b的游标
    int n;          //共几个区间
    int res = 1;    //全放到一个组中,最小,默认值1
    
    
    int main() {
        //优化输入
        ios::sync_with_stdio(false);
        //n个区间
        cin >> n;
        for (int i = 0; i < n; i++) {
            int l, r;
            cin >> l >> r;
            b[idx++] = l * 2;       //标记左端点为偶数;同比放大2倍,还不影响排序的位置,牛~
            b[idx++] = r * 2 + 1;   //标记右端点为奇数;同比放大2倍,还不影响排序的位置,牛~
        }
        //将所有端点放在一起排序,由小到大
        sort(b, b + idx);
    
        int t = 0;
        for (int i = 0; i < idx; i++) {
            if (b[i] % 2 == 0) t++; //左端点
            else t--;               //右端点
            res = max(res, t);      //动态计算什么时间点时,出现左的个数减去右的个数差最大,就是冲突最多的时刻
        }
        //输出结果
        printf("%d", res);
        return 0;
    }
    

    上面的代码是不允许存在任何两个结点开始与结束在同一个点的,比如1到3点,3到4点,算冲突。有时这样的不算冲突,就需要另一种方案:
    如果能区间端点能重合的话,是不是端点标记的奇数偶数反一下就行了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 100100;
    
    int b[2 * N];   //key,value:第几个端点,坐标值
    int idx;        //用于维护数组b的游标
    int n;          //共几个区间
    int res = 1;    //全放到一个组中,最小,默认值1
    
    
    int main() {
        //优化输入
        ios::sync_with_stdio(false);
        //n个区间
        cin >> n;
        for (int i = 0; i < n; i++) {
            int l, r;
            cin >> l >> r;
            b[idx++] = l * 2 + 1;       //标记左端点为奇数;同比放大2倍,还不影响排序的位置,牛~
            b[idx++] = r * 2;           //标记右端点为偶数;同比放大2倍,还不影响排序的位置,牛~
        }
        //将所有端点放在一起排序,由小到大
        sort(b, b + idx);
    
        int t = 0;
        for (int i = 0; i < idx; i++) {
            if (b[i] % 2) t++; //左端点
            else t--;          //右端点
            res = max(res, t); //动态计算什么时间点时,出现左的个数减去右的个数差最大,就是冲突最多的时刻
        }
        //输出结果
        printf("%d", res);
        return 0;
    }
    
    
  • 相关阅读:
    C#获取视频文件播放长度
    ViewState跨页传值
    radio点击事件
    js屏蔽鼠标右键
    js获取url参数
    js页面跳转
    android 界面刷新功能
    android RadioButton单选按钮效果
    android TextView实现跑马灯效果(字体滚动)
    android 圆角效果
  • 原文地址:https://www.cnblogs.com/littlehb/p/15470606.html
Copyright © 2011-2022 走看看