题意:数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1,t](1<=t<=1,000,000)。
覆盖整点,即[1,2]+[3,4]可以覆盖[1,4]。
不可能办到:输出-1
题解:本题为一题区间覆盖贪心问题
区间覆盖贪心题型:n个[ai,bi]区间,选择尽可能少的区间覆盖指定区间[s,t]。
贪心策略:左端点从小到大排序
贪心过程:设置一个变量end表示已覆盖到的区间右端点,另一个变量start为当前已覆盖到的区间右端点。
在所有左端点小于等于start的线段中,选择右端点最大的线段,更新end,并且初始化start=end+1,重复以上操作。
如果end<start,意味着end在下一段区间没法被更新,即不可能形成完整区间覆盖,因此跳出while。(一般用while循环)
贪心证明:要求用最少的线段进行覆盖,那么选取的线段必然要尽量长,而已覆盖到的区域之前的地方已经不用考虑了,能够使得线段更长取决于右端点,每次只要保证右端点尽可能大即可。
#include<stdio.h> #include<algorithm> #include<iostream> using namespace std; const int inf = 0x3f3f3f3f; struct node { int l; int r; }p[30000]; bool cmp(node a, node b) { if (a.l == b.l)return a.r > b.r; return a.l < b.l; } int main(void) { ios::sync_with_stdio(false); int N, T; cin >> N >> T; for (int i = 1; i <= N; i++) cin >> p[i].l >> p[i].r; sort(p + 1, p + N + 1, cmp); int start, ans = 0, i = 1, end = 0;//end表示当前这一区间能延伸到最远位置 while (end < T) { start = end + 1;//下一个区间的起点是上一个区间的终点+1 for (; i <=N ; i++) { if (p[i].l <= start) end = max(end, p[i].r); else break;//如果p[i].l在start之后,则认为是下一个区间 } if (end < start) { ans = -1; break; } ans++; } cout << ans << endl; return 0; }