传送门
看到数据范围不大,暴力走起。
枚举每一个圆,如果被完全覆盖直接退出。
否则如果被覆盖掉一部分就求出覆盖区间。
然后就是sb的区间覆盖问题了。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
using namespace std;
int n,top;
double ans,r[1005],x[1005],y[1005];
struct line{double l,r;}q[2005];
bool cmp(line a,line b){
return a.l<b.l;
}
double sqr(double x){return x*x;}
double dis(int a,int b){
return sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b]));
}
bool init(int a,int b){
return r[a]>=r[b]+dis(a,b);
}
void add(int a,int b){
double d,t,st,l;
d=dis(a,b);
t=(sqr(r[a])-sqr(r[b])+sqr(d))/(2*d);//余弦定理
st=atan2(x[a]-x[b],y[a]-y[b]);
l=acos(t/r[a]);
q[++top]=(line){st-l,st+l};
}
double cal(int x){
for (int i=x+1;i<=n;i++)
if (init(i,x)) return 0;
top=0;
for (int i=x+1;i<=n;i++)
if (!init(x,i)&&r[x]+r[i]>=dis(x,i))
add(x,i);
for (int i=1;i<=top;i++){
if (q[i].l<0) q[i].l+=2*pi;
if (q[i].r<0) q[i].r+=2*pi;
if (q[i].l>q[i].r){
q[++top]=(line){0,q[i].r};
q[i].r=2*pi;
}
}
sort(q+1,q+top+1,cmp);
double tmp=0,now=0;
for (int i=1;i<=top;i++)
if (q[i].l>now){
tmp+=q[i].l-now;
now=q[i].r;
}
else now=max(now,q[i].r);
tmp+=2*pi-now;
return r[x]*tmp;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
for (int i=1;i<=n;i++)
ans+=cal(i);
printf("%.3lf",ans);
}