UVALive - 2572 Viva Confetti 极角排序

题目链接点这里

大白上的经典题,,但是比较难想。。。

安装大白的思路,我们可以用圆弧的中点,前后偏移eps,用点代替圆弧里外的区域,就转化过来了。。。。

这题精度有毒,,,还是看了代码仓库里的代码,,才A的。。计算几何精度太麻烦了,,反正原则就是,,,对于,,sqrt(),cos,sin这些函数能不用就不用,,,对于除法也能不用就不用,,这些写法大概都需要积累吧。。。

//注意精度,直接用rad计算圆弧中点,
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<queue>
#include<string.h>
#include<string>
#include<cstring>
#include<vector>
#include<time.h>
#include<stdlib.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f3f
#define FIN freopen("input.txt","r",stdin);
#define mem(x,y) memset(x,y,sizeof(x));
typedef unsigned long long ULL;
typedef long long LL;
#define fuck(x) cout<<x<<endl;
const int  MX=333;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<pair<int,int>,int> PIII;
typedef pair<int,int> PII;
const double eps=5e-13;
const double PI=acos(-1);
struct Point
{
    double x, y;
    Point() {}
    Point(double x,double y):x(x),y(y) {}
};
typedef Point Vector;
int dcmp(double x)   //返回x的正负
{
    if(fabs(x)<eps)return 0;
    return x<0?-1:1;
}
Vector operator-(Vector A,Vector B)
{
    return Vector(A.x - B.x, A.y - B.y);
}
Vector operator+(Vector A,Vector B)
{
    return Vector(A.x + B.x, A.y + B.y);
}
Vector operator*(Vector A,double p)
{
    return Vector(A.x*p, A.y*p);
}
Vector operator/(Vector A,double p)
{
    return Vector(A.x/p, A.y/p);
}
bool operator<(const Point&a,const Point&b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
bool operator==(const Point&a,const Point&b)
{
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Vector A,Vector B)   //点积
{
    return A.x*B.x+A.y*B.y;//如果改成整形记得加LL
}
double Cross(Vector A,Vector B)   //叉积
{
    return A.x*B.y-A.y*B.x;//如果改成整形记得加LL
}
//向量长度
double Length(Vector A)
{
    return sqrt(Dot(A,A));
}
//2个向量之间的夹角
double Angle(Vector A,Vector B)
{
    return acos(Dot(A,B)/Length(A)/Length(B));
}
//向量的极角
double angle(Vector v)
{
    return atan2(v.y,v.x);
}
//计算ABC的有向面积
double Area(Point A,Point B,Point C)
{
    return Cross(B-A,C-A)/2;
}
//将A向量逆时针旋转rad
Vector Rotate( Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
//返回A的逆时针旋转90度的单位法向量
Vector Normal(Vector A)
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}
//计算2条直线P+tv和Q+tw的交点,请先确保不是平行(v!=w)
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
    Vector u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}
//P到直线AB的距离
double DistanceToLine(Point P,Point A,Point B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2))/Length(v1);
}
//计算P到线段AB的距离
double DistanceToSegment(Point P,Point A,Point B)
{
    if(A==B)return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0)return Length(v2);
    else if(dcmp(Dot(v1,v3))>0) return Length(v3);
    else return fabs(Cross(v1,v2))/Length(v1);
}
//点P在直线AB上的投影
Point GetLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));
}
//线段a1a2和b1b2的相交判定
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
           c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return (dcmp(c1)^dcmp(c2))==-2&&(dcmp(c3)^dcmp(c4))==-2;
}
//点p是否在线段a1a2上(不包含端点<,包含端点<=)
bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
//多边形面积
double PolygonArea(Point *p,int n)
{
    double area=0;
    for(int i=1; i<n-1; i++)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return fabs(area/2);
}
//园
struct Circle
{
    Point c;
    double r;
    Circle() {}
    Circle(Point c,double r):c(c),r(r) {}
    Point getpoint(double rad)
    {
        return Point(c.x+cos(rad)*r,c.y+sin(rad)*r);
    }
};
//有向线段
struct Line
{
    Point p;
    Vector v;//方向向量,左边为半平面
    double ang;//极角
    Line() {}
    Line(Point p,Vector v):p(p),v(v)
    {
        ang=atan2(v.y,v.x);
    }
    bool operator<(const Line &L)const   //极角排序
    {
        return ang<L.ang;
    }
    Point point(double t)
    {
        return p + v*t;
    }
    Line move(double d)   //向左边平移d单位
    {
        return Line(p + Normal(v)*d, v);
    }
};
//圆与园的交点
int GetCircleCircleIntersection(Circle C1, Circle C2, vector<double>& sol)
{
    double d = Length(C1.c - C2.c);
    if(dcmp(d) == 0)
    {
        if(dcmp(C1.r - C2.r) == 0) return -1; // 重合,无穷多交点
        return 0;
    }
    if(dcmp(C1.r + C2.r - d) < 0) return 0;//相离
    if(dcmp(fabs(C1.r-C2.r) - d) > 0) return 0;//内含
    double a = angle(C2.c - C1.c);
    double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
    // Point p1 = C1.getpoint(a-da), p2 = C1.getpoint(a+da);
    sol.push_back(a-da);
    if(dcmp(da)==0) return 1;//相切
    sol.push_back(a+da);//相交
    return 2;
}
int n;
Circle w[MX];
vector<Point> p;
vector<double>tmp;
bool vis[MX];
int main()
{
    while(cin>>n&&n)
    {
        p.clear();
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf",&w[i].c.x,&w[i].c.y,&w[i].r);
            // w[i].c.x*=1000,w[i].c.y*=1000,w[i].r*=1000;
        }
        mem(vis,0);
        for(int i=1; i<=n; i++)
        {
            tmp.clear();
            for(int j=1; j<=n; j++)
                if(i!=j)
                {
                    GetCircleCircleIntersection(w[i],w[j], tmp);
                }
            tmp.push_back(0);
            tmp.push_back(2*PI);
            sort(tmp.begin(),tmp.end());
            for(int j=0; j<tmp.size()-1; j++)
            {
                double mid=(tmp[j]+tmp[j+1])/2;
                //cout<<norm.x<<" "<<norm.y<<" "<<t<<endl;
                p.push_back(Point(w[i].c.x+cos(mid)*(w[i].r+eps),w[i].c.y+sin(mid)*(w[i].r+eps)));
                //cout<<(w[j].c+norm*t*(w[j].r+eps1)).x<<" "<<(w[j].c+norm*t*(w[j].r+eps1)).y<<" "<<t<<endl;
                //cout<<(w[j].r)<<endl;
                p.push_back(Point(w[i].c.x+cos(mid)*(w[i].r-eps),w[i].c.y+sin(mid)*(w[i].r-eps)));
                //cout<<p[p.size()-1].x<<" "<<p[p.size()-1].y<<" "<<t<<endl;
            }
        }
        for(int i=0; i<p.size(); i++)
        {
            // printf("%.16f %.16f\n",p[i].x,p[i].y);
            for(int j=n; j>=1; j--)
                if(dcmp(Length(p[i]-w[j].c)-w[j].r)<=0)
                {
                    vis[j]=1;
                    //cout<<j<<endl;
                    break;
                }
        }
        //cout<<p.size()<<endl;
        int ans=0;
        for(int i=1; i<=n; i++)if(vis[i])ans++;
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值