题意:数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1
思路:首先进行预处理,将不在区间[1, t]内的区间砍掉,然后按照左端点从小到大进行排序,当左端点相同时右端点从大到小排序,从起点开始选择区间,然后继续处理循环选择
总结:贪心问题关键找到多个指标,确定按哪个指标处理更优。
反思:刚开始TE,后来进行了优化,因为其实的区间是sort排好序的,所以可以在cover函数里面加入判断,预处理时不需要对所有预处理,而且每次都是选择起始点的区间,所以当区间起始点大于sx时说明以后的区间也不可取,所以break
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int flag = 0;
struct interval
{
int x, y;
bool operator<(const interval& a)
{
if (x != a.x) return x < a.x;
return y > a.y;
}
}ter[25002];
void cover(interval* ter, int k, int sx, int ty)
{
int num = -1; bool ok = 0; int snum;
for (int i = 0; i < k; i++)
{
if (ter[i].y<sx || ter[i].x>ty) continue;
if (ter[i].x < sx) ter[i].x = sx;
if (ter[i].y > ty) ter[i].y = ty;
if (ter[i].x == sx&&((ter[i].y-ter[i].x)>num))//判断区间//起始点与长度
{
num = ter[i].y - ter[i].x; ok = 1; snum = ter[i].y + 1;
}
if (ter[i].x >sx) break;
}if (ok)
{
sx = snum;
flag++;
}
else
{
if (sx > ty)
cout << flag;
else cout << "-1"; return;
}if (sx > ty)
{
cout << flag; return;
}
cover(ter, k, sx, ty);
}
int main()
{
int n, t; scanf("%d%d", &n, &t); int k = 0;
for (int i = 0; i < n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
if (y<1 || x>t) continue;
if (x < 1) x = 1;
if (y > t) y = t;
ter[i].x = x; ter[i].y = y; k++;
}
sort(ter, ter + k);
cover(ter, k, 1, t);
return 0;
}