区间覆盖
- 问题背景
给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 −1。
-
策略
- 将每个区间按左端点从小到大排序
- 从前往后枚举每个区间,在所有能覆盖 s 的区间中,选择右端点最大的区间,然后将 s 更新所选区间的右端点
练习
04 区间覆盖
- 题目
- 题解
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 100010;
public static int n, s, t;
public static Pair[] range = new Pair[N];
public static class Pair implements Comparable<Pair> {
public int first;
public int second;
public Pair(int first, int second) {
this.first = first;
this.second = second;
}
@Override
public int compareTo(Pair o) {
return this.first - o.first;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
String[] str1 = br.readLine().split(" ");
s = Integer.parseInt(str1[0]);
t = Integer.parseInt(str1[1]);
n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] str2 = br.readLine().split(" ");
range[i] = new Pair(Integer.parseInt(str2[0]), Integer.parseInt(str2[1]));
}
//左端点排序
Arrays.sort(range, 0, n);
int res = 0;
boolean flag = false;
//遍历所有区间
for (int i = 0; i < n; i++) {
//寻找左端点在s左边 且右端点最大的区间
int j = i;
//记录右端点最大值
int r = -(int) 2e9;
while (j < n && range[j].first <= s) {
r = Math.max(r, range[j].second);
j++;
}
//如果找到的右端点比s还小 说明这一段区间都无法覆盖s break
if (r < s) {
break;
}
//这个时候就找到了能覆盖s 且右端点最大的最佳区间 res++
res++;
//如果找到的这个区间同时也覆盖了t 那就找到了最后一个区间 flag置为true break
if (r >= t) {
flag = true;
break;
}
//更新s为右端点
s = r;
//由于s的更新 下一次的寻找就用不上已经遍历过的区间 更新一下
//这里体现了双指针算法
i = j - 1;
}
if (flag) {
pw.println(res);
} else {
pw.println(-1);
}
pw.close();
br.close();
}
}