区间覆盖问题,书上有分析但还是用了好久才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;
}