描述
You are given N intervals [S1, T1], [S2, T2], [S3, T3], … [SN, TN] and a range [X, Y]. Select minimum number of intervals to cover range [X, Y].
输入
The first line contains 3 integers N, X and Y. (1 <= N <= 100000, 1 <= X < Y <= 1000000)
The following N lines each contain 2 integers Si, Ti denoting an interval. (1 <= Si < Ti <= 1000000)
输出
Output the minimum number of intevals to cover range [X, Y] or -1 if it is impossible.
样例输入
5 1 5
1 2
1 3
2 4
3 5
4 5
样例输出
2
题意:
给n个区间 以及一个目标区间,问n个区间中最少可以由几个区间可以把目标区间覆盖。
思路:
一开始以为可以用dfs来做,每个区间起点和终点连边然后dfs求一个最短路径。后面发现,目标区间得起点,不一定是给定区间得起点,所以不能用这方法做。
正解是贪心。
具体来说,可以用以下贪心思路解决本题:
首先找到一个起点 <= X,并且终点尽量大(靠右)的区间,选为第一个区间。不妨设这个区间的终点是R[1]。
然后再找一个起点 <= R[1],并且终点尽量大的区间,选为第二个区间。不妨设这个区间的终点是R[2]。
重复以上步骤,直到某个R[k]满足R[k] >= Y,这时R[1] … R[k]即是一组最优的区间,k即是答案。
如果在中间某一步发现R[k] == R[k-1],说明做不到覆盖整个[X, Y],输出-1。
以上贪心算法最关键的就是找起点 <= 某个值,同时终点尽量大的区间。
我们可以将所有区间按起点排序,然后从头到尾扫描即可完成以上的查找。复杂度是排序O(NlogN) + 扫描贪心O(N)。
#include <bits/stdc++.h>
using namespace std;
struct Node {
int x,y;
};
vector<Node>A;
bool cmp(Node a, Node b) {
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
void solve(vector<Node>&A,int s, int t) {
sort(A.begin(),A.end(),cmp);
int res = 0;
vector<Node>B;
int idx = 0;
int nows = s;
int nowt = 0;
int i;
while(1) {
for (i = idx; i < (int)A.size(); ++i) {
if (A[i].x <= s && A[i].y > nowt) {
nows = A[i].x;
nowt = A[i].y;
idx = i;
}
}
++res;
Node tmp;
tmp.x = nows;
tmp.y = nowt;
//cout << nows << " " << nowt << " "<< idx << endl;
if (B.size() != 0 && B.back().y == tmp.y) {
cout << "-1"<<endl;
return;
}
B.push_back(tmp);
if (nowt >= t) break;
else {
idx = idx+1;
s = nowt;
}
}
if (nowt < t) cout << "-1"<<endl;
else
cout << res << endl;
}
int main () {
int n,s,t,x,y;
cin >> n >> s >> t;
for (int i = 0; i < n; ++i) {
cin >> x >> y;
Node tmp;
tmp.x = x;
tmp.y = y;
A.push_back(tmp);
}
solve(A,s,t);
}