10382 - Watering Grass(贪心 区间覆盖问题)洒水面覆盖

double qiuzhi(int id)
{
    double t1=cc[id].rid*cc[id].rid;
    double t2=w*w/4;
    double t3=t1-t2;
    double t4=sqrt(t3);
    return t4;
}

void to_qujian()
{
    for(int i=0; i<t; i++)
    {
        double zhi=qiuzhi(i);
        qq[i].a=cc[i].pos-zhi;
        qq[i].b=cc[i].pos+zhi;
    }
}

典型的贪心区间覆盖问题,刘汝佳书上有讲,只有思路没有代码~他总是这么令人蛋疼。。


对本题来说,关键的一点在于由具体问题向“区间”的抽象~!用圆与矩形边的交点作为区间的左右端点!



用了两种方法,按书上的方法,采取多次截取合适区间的方法做了一遍,代码比较清晰实现出来了,但是超时。

原因已经分析清楚,本以为是0(n)的复杂度,但是忽略了排序的n log(n)的复杂度,每次循环都排序,10000的数据量超时是意料之中的事情。

#include<cstdio>//这是超时的代码~看清楚了~~
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=10000+10;
int n,t;
double l,w;
int flag1,flag2;

struct circle
{
    double pos;
    double rid;
} cc[maxn];
struct qujian
{
    double a;
    double b;
} qq[maxn];
void input(int n,double l,double w)
{
    t=0;
    int temp=n;
    for(int i=0; i<temp; i++)
    {
        double a1,b1;
        scanf("%lf%lf",&a1,&b1);
        if(b1<=w/2)
        {
            n--;
            continue;
        }
        else
        {
            cc[t].pos=a1;
            cc[t++].rid=b1;
        }
    }
}

bool cut_qujian(double left,double right)
{
    flag1=0;
    flag2=0;
    for(int i=0; i<t; i++)
    {
        if(qq[i].a<=left)
        {
            flag1=1;
            qq[i].a=left;
        }
        if(qq[i].b>=right-0.0000000001)
        {
            flag2=1;
            qq[i].b=right;
        }
    }
    if(flag1==1&&flag2==1)
        return true;
    else
        return false;
}
double qiuzhi(int id)
{
    double t1=cc[id].rid*cc[id].rid;
    double t2=w*w/4;
    double t3=t1-t2;
    double t4=sqrt(t3);
    return t4;
}

void to_qujian()
{
    for(int i=0; i<t; i++)
    {
        double zhi=qiuzhi(i);
        qq[i].a=cc[i].pos-zhi;
        qq[i].b=cc[i].pos+zhi;
    }
}


int cmp(qujian a,qujian b)
{
    if(a.a!=b.a) return a.a<b.a;
    else return a.b>b.b;
}

int main()
{
    while(scanf("%d%lf%lf",&n,&l,&w)!=EOF)
    {
        input(n,l,w);
        to_qujian();
        double left=0,right=l;
        int ans=-1;
        int cnt=0;
        while(cut_qujian(left,right))
        {
            cnt++;
            sort(qq,qq+t,cmp);
            left=qq[0].b;
            if(left>=right)
            {
                ans=1;
                break;
            }
        }
        if(ans==-1)
        {
            printf("-1\n");
        }
        else
            printf("%d\n",cnt);
    }
    return 0;
}


然后思路肯定是不能换,就换实现的方式好了~

用了下面这种看似0(n^2),但实际上复杂度为0(n)的方法,学长给的,觉得很好。


#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=10000+10;
int n,t;
double l,w;
int flag1,flag2;

struct circle
{
    double pos;
    double rid;
} cc[maxn];
struct qujian
{
    double a;
    double b;
} qq[maxn];
void input(int n,double l,double w)
{
    t=0;
    int temp=n;
    for(int i=0; i<temp; i++)
    {
        double a1,b1;
        scanf("%lf%lf",&a1,&b1);
        if(b1<=w/2)
        {
            n--;
            continue;
        }
        else
        {
            cc[t].pos=a1;
            cc[t++].rid=b1;
        }
    }
}
double qiuzhi(int id)
{
    double t1=cc[id].rid*cc[id].rid;
    double t2=w*w/4;
    double t3=t1-t2;
    double t4=sqrt(t3);
    return t4;
}

void to_qujian()
{
    for(int i=0; i<t; i++)
    {
        double zhi=qiuzhi(i);
        qq[i].a=cc[i].pos-zhi;
        qq[i].b=cc[i].pos+zhi;
    }
}


int cmp(qujian a,qujian b)
{
    return a.a<b.a;
}

int solve()
{
    int cnt=0;
    double right=0;
    for(int i=0; i<t; i++)
    {

        double nowr=right;
        for(; qq[i].a<=right; i++)
        {
            if(qq[i].b>nowr)
                nowr=qq[i].b;
        }
        if(nowr==right) return -1;
        right=nowr;
        cnt++;
        i--;
    }
    if(right<l) return -1;
    return cnt;
}
int main()
{
    while(scanf("%d%lf%lf",&n,&l,&w)!=EOF)
    {
        input(n,l,w);
        to_qujian();
        int ans;
        sort(qq,qq+t,cmp);
        ans=solve();
        if(ans==-1)
        {
            printf("-1\n");
        }
        else
            printf("%d\n",ans);
    }
    return 0;
}

好久都没能有像做这道题目的感受了,感觉很好。


你可能感兴趣的:(贪心,区间覆盖)