POJ 2376 Cleaning Shifts(贪心)
Description
有一段从1到n的区间,现有多条线段(左右界不同,有重合区域),求最少需几条线段才能覆盖整个大区间?
Analyze
我知道选择一个区间要尽可能选右界大的,于是我按右界排序,后来发现做不了……这题应该明确:在左界能承接上一个区间的前提下选右界最大的。我一直难以做到左右兼顾,按左界排序?按右界排序?先左后右?先右后左?没有合适的排序方式。后来发现贪心有它的前提和选择。
贪心前提:左界承接前段
贪心选择:右界选择最右
我们得先满足前提,后贪心选择。
那就按左界从小到大排序,保证左边的是满足前提的,while去遍历
遍历过程中用
right = max(right, a[pos].r)
来贪心选择最右的更新右界,再从上次停止的位置起重复上述过程
Attention:
上次停止的位置(设为pos)是满足条件的最右的位置,更新后的右界(设为right)是遍历过程中最右的界线,right >= a[pos].r >= a[pos].l,所以这个方法只需要遍历一遍,O(n)
Code
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
struct node
{
int l, r;
} a[25005];
bool cmp(node a, node b)
{
return a.l < b.l;
}
int main()
{
int n, t;
scanf("%d%d", &n, &t);
for(int i = 0; i < n; ++i)
scanf("%d%d", &a[i].l, &a[i].r);
sort(a, a + n, cmp);
int r = 0, pos = 0, ans = 0;
while(r < t)
{
int rmax = -1;
while(a[pos].l <= r + 1)
{
rmax = max(rmax, a[pos].r);
pos++;
}
if(rmax == -1)
{
cout << "-1" << '\n';
return 0;
}
ans++;
r = rmax;
}
cout << ans << '\n';
return 0;
}
///4 10
///1 5
///2 10
///9 10
///3 9