#计算几何,极角排序#洛谷 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;
}
posted @ 2025-07-15 03:50  lemondinosaur  阅读(9)  评论(0)    收藏  举报