P2510 [HAOI2008]下落的圆盘

题意

考虑算出每个圆能露出的部分,我们可以枚举它之后的圆,算出它被覆盖多少。

我们可以通过极角序将周长变为([0,2pi])的区间,这样问题就变为了给出一些区间,问([0,2pi])被这些去区间覆盖后还剩多少。

计算圆(b)覆盖圆(a)
先判断是否存在包含和相离的情况。

我们求出(t1=angle{EAB})(t2=angle{DAB}),那么(l=t1-t2,r=t1+t2)
如果(l,r)中有小于(0)的,就让它加上(2pi)
如果(r<l)那么覆盖的区间为([l,2pi],[0,r])

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const double eps=1e-8;
const double Pi=acos(-1.0);
int n,m,tot;
double ans;
bool flag;
struct Point
{
    double x,y;
    inline double len(){return sqrt(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 k){return (Point){x*k,y*k};}
    Point operator/(const double k){return (Point){x/k,y/k};}
    double operator*(const Point a)const{return x*a.y-y*a.x;}
    double operator&(const Point a)const{return x*a.x+y*a.y;}
};
inline int dcmp(double x)
{
	if(fabs(x)<=eps)return 0;
	return x<0?-1:1;
}
inline double dis(Point a,Point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
struct Circle{Point p;double r;}cir[maxn];
struct Seq{double l,r;}seq[maxn<<1];
inline bool cmp(Seq a,Seq b){return !dcmp(a.l-b.l)?dcmp(a.r-b.r)<0:dcmp(a.l-b.l)<0;}
inline bool check1(Circle a,Circle b){return dcmp((b.r-(dis(a.p,b.p)+a.r)))>=0;}
inline bool check2(Circle a,Circle b){return dcmp(dis(a.p,b.p)-(a.r+b.r))>=0;}
inline double sqr(double x){return x*x;}
inline void work(Circle a,Circle b)
{
	double d,l,r,t1,t2;
	d=dis(a.p,b.p);
	t1=atan2(b.p.y-a.p.y,b.p.x-a.p.x);
	t2=acos((sqr(a.r)+sqr(d)-sqr(b.r))/(2.0*d*a.r));
	l=t1-t2,r=t1+t2;
	if(dcmp(l)<0)l+=2.0*Pi;
	if(dcmp(r)<0)r+=2.0*Pi;
	if(dcmp(l-r)<=0)seq[++tot]=(Seq){l,r};
	else seq[++tot]=(Seq){l,2.0*Pi},seq[++tot]=(Seq){0,r};
}
inline double solve(int x)
{
	for(int i=x+1;i<=n;i++)if(check1(cir[x],cir[i]))return 0;
	tot=0;
	for(int i=x+1;i<=n;i++)if(!check1(cir[i],cir[x])&&!check2(cir[i],cir[x]))work(cir[x],cir[i]);
	sort(seq+1,seq+tot+1,cmp);
	double res=0,now=0;
	for(int i=1;i<=tot;i++)
		if(seq[i].l>now)res+=seq[i].l-now,now=seq[i].r;
		else now=max(now,seq[i].r);
	res+=2*Pi-now;
	return res*cir[x].r;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&cir[i].r,&cir[i].p.x,&cir[i].p.y);
	for(int i=1;i<=n;i++)ans+=solve(i);
	printf("%.3lf",ans);
	return 0;	
}
原文地址:https://www.cnblogs.com/nofind/p/12212502.html