UVa:10020 Minimal coverage

 

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


 

你可能感兴趣的:(贪心法)