【题目大意】
给出几个小区间和大区间,求覆盖整个大区间的最少小区间个数,如果不可能则输出-1。
【思路】
这道程序写得我很不爽快,迷迷糊糊写完了,提交一遍AC了,可是我自己都没怎么弄懂到底是怎么写出来的(我果然不是很擅长贪心的实现)。思路很简单,显而易见地贪心,关键在于如何实现这个思路。
先以区间左边界为关键字进行排序,每次选左边界能与上一个右边界相接的区间中右边界最大的那一个。我的实现方法是这样的:假设当前已经覆盖区域的右边界为lright,之前能覆盖到的最大右边界为p,ans为需要的小区间数。对于每一个小区间:
(1)如果它的左边界已经大于lright+1,即p已经是能与上一个右边界相接的区间中右边界最大的那一个,将lright更新为p,p初始化为-1,ans+1;当然,如果p本身就是-1,说明无法与已覆盖区域连接,无解(当然无解的情况并不仅限于这一种,还有可能是无法覆盖到大区间的右边界等),可以直接退出循环。
(2)如果当前左边界小于等于lright+1,且右边界大于等于lright+1,在当前右边界和p中选取较大的一个;如果p恰好大于等于大区间的右边界,ans+1,退出循环。
要注意的一点事,所谓衔接不是[0,1][1,2]这样首尾相接,而是[0,1][2,3]即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int MAXN=1000000+50; 8 struct interval 9 { 10 int left,right; 11 bool operator < (const interval &x) const 12 { 13 return (left<x.left); 14 } 15 }; 16 17 int n,t; 18 interval cow[MAXN]; 19 20 int main() 21 { 22 scanf("%d%d",&n,&t); 23 for (int i=0;i<n;i++) 24 scanf("%d%d",&cow[i].left,&cow[i].right); 25 sort(cow,cow+n); 26 27 int lright=0,ans=0,p=-1; 28 for (int i=0;i<n;i++) 29 { 30 if (cow[i].left>lright+1) 31 { 32 if (p==-1) break; 33 /*如果当前左边界已经大于之前的最大右边界,且没有中间区间能衔接,必定说明无解*/ 34 ans++; 35 lright=p; 36 p=-1; 37 /*否则将已经覆盖区域的右边界设为之前最大的右边界*/ 38 } 39 if (cow[i].left<=lright+1 && cow[i].right>=lright+1) 40 { 41 p=max(p,cow[i].right); 42 if (p>=t) 43 { 44 ans++; 45 break; 46 /*如果当前已经覆盖完大区间,就退出*/ 47 } 48 } 49 } 50 if (p>=t) cout<<ans<<endl; 51 else cout<<-1<<endl; 52 53 return 0; 54 }