LA 2572 圆盘的相互覆盖问题,圆弧极角排序,中点代替圆弧,轻微扰动的影响判断

来源:互联网 发布:淘宝体检中心链接 编辑:程序博客网 时间:2024/04/30 00:38

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<string>#include<set>#include<vector>#include<map>#define LL long longusing namespace std;const double eps=5*1e-13;const double PI=acos(-1.0);int  dcmp(double x){    if(fabs(x)<eps)        return 0;    return x>0?1:-1;}struct point{    double x,y;    point() {}    point(double x,double y):x(x),y(y){}    point operator + (const point &a) const    {        return point(x+a.x,y+a.y);    }    point operator - (const point &a) const    {        return point(x-a.x,y-a.y);    }    point operator * (const double &a) const    {        return point(x*a,y*a);    }    point operator / (const double &a) const    {        return point(x/a,y/a);    }    bool operator <(const point &a)  const    {        return (x+eps<a.x||(!dcmp(x-a.x)&&y<a.y));    }    double len()    {        return sqrt(x*x+y*y);    }    point normal()    {        return point(-y,x)/len();    }    void in()    {        cin>>x>>y;    }};double dis(point a,point b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double angle(point v){    return atan2(v.y,v.x);}struct Circle{    point o;    double r;    Circle() {}    Circle(point o,double r):o(o),r(r){}    point getpoint(double a)    {        return point(r*cos(a),r*sin(a))+o;    }    void in()    {        o.in();        cin>>r;    }};void getCircleCircleIntersection(Circle C1,Circle C2,vector<double> &sol){    point u=C1.o-C2.o;    double d=u.len();    if(dcmp(d)==0) return ;    if(dcmp(C1.r+C2.r-d)<0) return ;    if(dcmp(fabs(C1.r-C2.r)-d)>0) return ;    double a=angle(C2.o-C1.o);    double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));    sol.push_back(a+da);    sol.push_back(a-da);}Circle C[110];int n;int topmost(point p){  //  cout<<p.x<<" "<<p.y<<endl;    for(int i=n-1;i>=0;i--)    {       // cout<<dis(C[i].o,p)<<endl;        if(dis(C[i].o,p)<C[i].r) return i;    }    return -1;}int main(){    while(cin>>n&&n)    {        for(int i=0;i<n;i++)            C[i].in();        set<int> ret;        for(int i=0;i<n;i++)        {            vector<double> sol;            for(int j=0;j<n;j++)                getCircleCircleIntersection(C[i],C[j],sol);            sol.push_back(0);            sol.push_back(PI*2);            sort(sol.begin(),sol.end());            for(int j=0;j<sol.size();j++)            {              // cout<<sol[j]<<endl;                double mid=(sol[j]+sol[j+1])/2.0;                for(int d=-1;d<=1;d+=2)                {                   double r2=C[i].r-d*eps;                    //cout<<r2<<endl;                    point a(C[i].o.x+cos(mid)*r2,C[i].o.y+sin(mid)*r2);                    int t=topmost(a);                    if(t>=0) ret.insert(t);                }            }        }        cout<<ret.size()<<endl;    }    return 0;}

本人比较弱,看到题之后没思路,找题解,题解解释如下:

平面上给n个圆盘,有先后顺序的叠放在一起,求最后有多少个是可见的。

只要没有被完全遮住就是可见的。

首先,要是我们能枚举所有的点,找到覆盖这个点的圆盘中,最上面的,那么这个圆一定时可见的,否则被遮住,那么它不是最上面的。

好了,那么只要给一个点,找到topmost那务必是符合要求的,

现在就想怎么找到所有符合要求的圆盘。

对一个可见的圆盘,它必定至少有一部分是可见的,这一部分,必定是由圆弧组成,对于这块圆弧组成的区域,再没有任何圆盘去覆盖,我们取区域内的一个点的topmost一定能找到它。1那我们就取弧的中点,偏向一点2怎么取到内部? r+-eps,不是加就是减,总之取多了没关系,没漏掉就好。(微小扰动没关系--+-eps一定还在内部)。

然后是,样例的点都精确到e-11了,eps显然要提高。

看了题解后,自己敲了一份代码,发现不对,DBUG了好久发现竟然是调用一个函数时忘记加括号了,由此来看,敲程序一定要认真,一点小错误都会导致满盘皆输。

贴上我的代码:


0 0
原创粉丝点击