区间覆盖问题,书上有分析但还是用了好久才AC掉。
用贪心法,依据每条线段的起点排序,依次扫描在线段起点小于等于区间左端点(初始为0)的前提下,选取有效长度最长(即线段终点最大)的那条线段的终点作为新区间的起点,然后继续像开始那样扫描直至所得线段终点大于等于区间右端点。
线段尽量长才能保证覆盖区间尽量大,才使得所用线段尽量少,这是贪心的关键。
我写的代码中有一些细节需要注意。
比如说确定最大有效长度的过程是使用了一个新的循环,结束循环的条件是出现起点小于区间左端点的线段。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; struct Segment { int l,r; }; Segment x[100005]={0}; bool cmp(Segment a,Segment b) { return a.l<b.l; } int main() { // freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--) { int m,n=0; int a,b; scanf("%d",&m); while(scanf("%d%d",&a,&b)==2&&!(!a&&!b)) { if(b<=0||a>=m) continue; x[n].l=a; x[n++].r=b; } sort(x,x+n,cmp); int y[100005]={0}; int L=0,t=0,max=0,count=0; for(int i=0;i<n;++i) { if(x[i].r<=L) continue; if(x[i].l<=L) { int j; for(j=i;j<n;j++) { if(x[j].l<=L&&x[j].r>max) {max=x[j].r;t=j;} if(L<x[j].l) break; } L=max; y[count++]=t; if(L>=m) break; } } if(L<m||x[0].l>0) count=0; printf("%d\n",count); for(int i=0;i<count;i++) printf("%d %d\n",x[y[i]].l,x[y[i]].r); if(T) printf("\n"); } return 0; }