一、区间完全覆盖问题
题目
给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖。
解析
先将所有线段按起点从小到大排序。排完序后,枚举每一个线段(被其它线段包含的线段不用考虑,因为很明显包含它的线段比它更优),将其作为最左端的线段,
再在剩下的左端点小于等于最左端的线段的右端点的线段中(若没有则无解),找到右端点最大的一个线段,即贪心,很显然这是最优的,因为其左端都被最左端的线段覆盖了,
也就没有覆盖到任何地方,则其右端点越大,其右端覆盖到的地方也就最优。
反复重复上一步,直到覆盖完整个长度为m的区间,就能得到最少的线段数。
Code
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> using namespace std; struct rec{ int l,r; }a[1001]; bool cmp(rec x,rec y) { return x.l<y.l; //按左端点从小到大排 } int m,n,ll,minn=0x7f7f7f7f; void q(int x,int ans) { if(a[x].r-ll>=m-1) //覆盖总长度达到 { minn=min(minn,ans); return ; } int temp=0; for(int i=x+1;i<=n;i++) { if(a[i].l<=a[x].r) //找左端点小于当前线段右端点的 { if(a[i].r>a[temp].r) temp=i; //找右端点最大区间 } else break; //顺序排序,如果左端点大于当前线段右端点,后面肯定也大于 if(temp!=0) q(temp,ans+1); } } int main() { a[0].r=-1; //特殊处理 cin>>m>>n; for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r; sort(a+1,a+n+1,cmp); //顺序排序 for(int i=1;i<=n;i++) { ll=a[i].l; //记录起点 q(i,1); } cout<<minn; return 0; }