洛谷P2510 [HAOI2008]下落的圆盘(计算几何)

题面

传送门

题解

对于每个圆,我们单独计算它被覆盖的周长是多少

只有相交的情况需要考虑,我们需要知道相交的那段圆弧的角度,发现其中一个交点和两个圆的圆心可以构成一个三角形且三边都已经知道了,那么我们可以根据余弦定理计算出这段圆弧的余弦进而用\(acos\)计算出角度

然而现在有个尴尬的问题是一段圆弧可能会被多次覆盖。那么我们考虑把相交的圆弧的左右端点用极角来表示,并把这个看成一条线段,那么最后只要求出线段覆盖就行了

顺便注意转化为极角的时候如果极角是负的要加上\(2\pi\),如果这时候\(l>r\),就拆成\([l,2\pi]+[2\pi,r]\)的形式

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
double readdb()
{
    R double x=0,y=0.1,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(x=ch-'0';(ch=getc())>='0'&&ch<='9';x=x*10+ch-'0');
    for(ch=='.'&&(ch=getc());ch>='0'&&ch<='9';x+=(ch-'0')*y,y*=0.1,ch=getc());
    return x*f;
}
const int N=2005;const double Pi=acos(-1.0);
struct point{double r,x,y;}p[N];
struct node{
	double l,r;
	node(){}
	node(R double ll,R double rr):l(ll),r(rr){}
	inline bool operator <(const node &b)const{return l<b.l;}
}st[N];
int n,top;double res;
inline double dis(R int i,R int j){return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));}
inline int in(R int i,R int j){return p[j].r>=p[i].r+dis(i,j);}
void calc(int pos){
	fp(i,pos+1,n)if(in(pos,i))return;
	top=0;
	fp(i,pos+1,n){
		R double d=dis(pos,i);if(in(i,pos)||p[i].r+p[pos].r<=d)continue;
		R double t=acos((d*d+p[pos].r*p[pos].r-p[i].r*p[i].r)/(2*p[pos].r*d));
		R double b=atan2(p[i].y-p[pos].y,p[i].x-p[pos].x);
		st[++top]=node(b-t,b+t);
		st[top].l<0?st[top].l+=2*Pi:0;
		st[top].r<0?st[top].r+=2*Pi:0;
		st[top].l>st[top].r?(st[top+1]=node(0,st[top].r),st[top++].r=2*Pi):0;
	}
	sort(st+1,st+1+top);
	R double now=0,tmp=0;
	fp(i,1,top)now<st[i].l?(tmp+=st[i].l-now,now=st[i].r):cmax(now,st[i].r);
	res+=p[pos].r*(tmp+2*Pi-now);
}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read();
	fp(i,1,n)p[i].r=readdb(),p[i].x=readdb(),p[i].y=readdb();
	fp(i,1,n)calc(i);
	printf("%.3lf\n",res);
	return 0;
}
posted @ 2019-03-11 21:24  bztMinamoto  阅读(216)  评论(0编辑  收藏  举报
Live2D