区间分组 -- 活动安排问题

一.题目

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

输出最小组数。

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

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

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

数据范围
1≤N≤105,
−109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例:
2

解答
思路1
将结点按照左端点排序,然后使用优先队列(小根堆)PriorityQueue存储每个点的右端点。若待测点的左端点 <= 右端点的最小值,则开新组;否则将其放入该右端点所在的组,同时更新小根堆。

//按照左端点排序
import java.io.*;
import java.util.*;

class Range implements Comparable<Range>{
    public int l;
    public int r;
    public Range(int l, int r) {
        this.l = l;
        this.r = r;
    }
    public int compareTo(Range r) {
        return this.l - r.l;
    }
}

public class Main{
    private static int N = 100010;
    private static List<Range> list = new ArrayList<>();
    //优先队列也就是小根堆:存储右端点
    private static PriorityQueue<Integer> heap = new PriorityQueue<>(); 
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        while(n-- > 0)
        {
            int a = sc.nextInt();
            int b = sc.nextInt();
            list.add(new Range(a, b));            
        }
        
        //排序
        list.sort((e1, e2) -> e1.l - e2.l);
        
        for(int i = 0;i < list.size();i ++)
        {
            Range t = list.get(i);
            int l = t.l, r = t.r;
            if(heap.isEmpty() || heap.peek() >= l)
            {
                heap.add(r); //新组
            }else {
                heap.poll();
                heap.add(r);
            }
        }
        
        System.out.println(heap.size());
    }
}

思路二
求最大区间厚度的问题
有若干个活动,第i个活动开始时间和结束时间是[Si, Fi],同一个教室安排的活动时间不能重合,那么安排所有活动,至少需要多少个教室?

把所有开始时间和结束时间排序,遇到开始时间就把教室数加1,遇到结束时间则减1。峰值就是我们至少需要的教室数。

//按照左端点排序
import java.io.*;
import java.util.*;


public class Main{
    private static int N = 100010;
    private static int idx = 0;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        
        int[] num = new int[n*2];
        //左端点:偶数,右端点:奇数
        while(n-- > 0)
        {
            int a = sc.nextInt();
            int b = sc.nextInt();
            num[idx ++]  = a*2;
            num[idx ++] = b*2+1;
        }
        
        Arrays.sort(num);
        
        int res = 1, t = 0;
        for(int i = 0;i < idx;i ++)
        {
            if(num[i] % 2 == 0) t ++; //遇到开始+1
            else t --; //遇到结束-1
            res = Math.max(res, t);
        }
        
        System.out.println(res);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值