题目
描述
数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1
输入
第一行:N和T
第二行至N+1行: 每一行一个闭区间。
输出
选择的区间的数目,不可能办到输出-1
样例输入
3 10
1 7
3 6
6 10
样例输出
2
思路
这道题与之前的B题有点类似,都与区间有关、都可以用贪心算法解决;但又很不一样,从题目就可以得知,这道题的目的是在输入的区间中选出最少的区间以覆盖[1,T]上的整数点(1,2,…,T)。
为了选择最少的区间同时又覆盖所有的整数点,于B题类似,我们需要对区间进行排序,不过这次是按区间的覆盖范围进行排序:
① 左端点的值越小越往前排
② 左端点相同时,右端点的值越大越往前排(覆盖范围越广)
例如,输入区间:
排序后:
然后开始选择区间。第一轮,先选择左端点为1(或包含1)且覆盖范围最大的区间,然后将该区间的右端点的值+1作为新的起点。第二轮,选择左端点为新的起点(或包含新的起点)且覆盖范围最大的区间,再将该区间的右端点的值+1作为新的起点······如此循环下去,直至某一轮结束后,新的起点大于T,此时说明已选择的区间已经将[1,T]中的整数点覆盖完了。其中,区间的覆盖范围 = 右端点 - 新的起点。
如图:
为了加快排序,我使用了STL中的优先队列,因为优先队列相当于栈,排序的时间复杂度为O(NlogN)。同时,当从队列中取出某个区间,且该区间的整体都在新起点的左端时,说明该区间上的点都已经被覆盖了,则可以舍弃该区间,以减少区间的数量和排序时间。
需要注意的是,在给区间排序后,若取出的第一个区间不包含1,则说明无法覆盖到1,即可提前结束退出;当新的起点 < T且再也无法选择下一个能覆盖的区间时,说明所给区间不足以覆盖所有的整数点,也可以结束退出。
代码
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
struct range {
int left, right;
range(int theLeft, int theRight) { left = theLeft; right = theRight; }
bool operator < (const range & r)
{
if (left != r.left) return left > r.left;
else return right < r.right;
}
};
struct cmp {
bool operator()(range r1, range r2)
{
if (r1.left != r2.left) return r1.left > r2.left;
else return r1.right < r2.right;
}
};
int n, t;
priority_queue<range, vector<range>, cmp> q;
int next_start;
int start;
bool found;
int cnt;
int main()
{
while (cin >> n >> t) {\
next_start = 1;
start = 1;
found = false;
cnt = 0;
for (int i = 0; i < n; i++) {
int a, b;
cin >> a >> b;
if (b<1 || a>t) continue;
q.push(range(a, b));
}
if (q.top().left > 1) {
cout << -1 << endl;
continue;
}
while (!q.empty() && start <= t) {
while (!q.empty()) {
range p = q.top();
q.pop();
int a = p.left, b = p.right;
if (b < start) continue;
else if (a <= start) {
if (next_start <= b) {
next_start = b + 1;
found = true;
}
}
else if (a > start&& found) {
q.push(range(a, b));
break;
}
else if (a > start && !found) goto over;
}
start = next_start;
cnt++;
found = false;
}
over:
if (start <= t) cout << -1 << endl;
else cout << cnt << endl;
}
}