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

本文介绍了一种解决平面上多个圆盘堆叠时如何判断哪些圆盘可见的问题。通过枚举圆盘间的交点并利用微小扰动来确定可见性的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<set>
#include<vector>
#include<map>
#define LL long long
using 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了好久发现竟然是调用一个函数时忘记加括号了,由此来看,敲程序一定要认真,一点小错误都会导致满盘皆输。

贴上我的代码:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值