#计算几何,极角排序#洛谷 2510 [HAOI2008] 下落的圆盘
分析
覆盖相当于有一段弧不归该圆所有,因此能改变某个圆的存在的弧只能是完全覆盖或者相交,
那么相交就可以判断它的弧被覆盖的部分,而覆盖的部分是可以变成 \([0,2\pi]\) 的子区间,
那么就是求出区间并然后减掉就行,覆盖的部分可以通过求出交点与圆心连线夹角和圆心斜率求出区间。
代码
#include <iostream>
#include <iomanip>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=1011;
const double pi=acos(-1.0);
pair<double,double>b[N<<1];
int n,m; double R[N],X[N],Y[N],ans;
void doit(int &flag,int A,int B){
double dist=sqrt((X[A]-X[B])*(X[A]-X[B])+(Y[A]-Y[B])*(Y[A]-Y[B]));
if (R[A]+R[B]<=dist||dist<=R[A]-R[B]) return;
if (dist<=R[B]-R[A]) {flag=0; return;}
double theta=atan2(Y[B]-Y[A],X[B]-X[A]),delta=acos((R[A]*R[A]+dist*dist-R[B]*R[B])/(2*R[A]*dist));
double l=theta-delta,r=theta+delta;
if (r<0) l+=2*pi,r+=2*pi;
if (l<0) b[++m]=make_pair(0,r),b[++m]=make_pair(l+2*pi,2*pi);
else b[++m]=make_pair(l,r);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1;i<=n;++i) cin>>R[i]>>X[i]>>Y[i];
for (int i=1;i<=n;++i){
int flag=1; m=0;
for (int j=n;j>i&&flag;--j) doit(flag,i,j);
if (flag){
sort(b+1,b+1+m);
double lst=b[1].first,sum=0;
for (int j=1;j<=m;++j){
if (b[j].second<=lst) continue;
sum+=b[j].second-max(lst,b[j].first);
lst=b[j].second;
}
ans+=(2*pi-sum)*R[i];
}
}
cout<<fixed<<setprecision(3)<<ans;
return 0;
}

浙公网安备 33010602011771号