BZOJ 1043 [HAOI2008]下落的圆盘

    xiaoxiao2022-06-23  38

    三角函数计算+区间合并

    对于每一个圆,判断接下来掉落的圆是否会覆盖它,用余弦定理之类的三角函数搞一搞就好了。计算出被覆盖的角的区间,然后并一下。

    #include<cstdio> #include<cmath> #include<algorithm> #define N 1005 using namespace std; struct circle { double r, x, y; }c[N]; struct interval { double l, r; }inter[N<<1]; const double eps = 1e-7, pi = acos(-1.0); int icnt; bool cmp(interval a, interval b){return a.l<b.l||(a.l==b.l&&a.r>b.r);} void solve(circle a, circle b) { double dis=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); if(dis>=a.r+b.r+eps)return; if(dis<=b.r-a.r+eps) { inter[++icnt]=(interval){-pi,pi}; return; } if(dis<=a.r-b.r+eps) return; double angle = atan2(b.y-a.y,b.x-a.x); double angle2 = acos( (dis*dis+a.r*a.r-b.r*b.r)/(2*a.r*dis) ); double la = angle-angle2, ra = angle+angle2; if(la<-pi) { inter[++icnt]=(interval){la+2*pi,pi}; inter[++icnt]=(interval){-pi,ra}; } else if(ra>pi) { inter[++icnt]=(interval){la,pi}; inter[++icnt]=(interval){-pi,ra-2*pi}; } else inter[++icnt]=(interval){la,ra}; } int main() { int n; double ans=0; scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%lf%lf%lf",&c[i].r,&c[i].x,&c[i].y); for(int i = 1; i <= n; i++) { icnt=0; for(int j = i+1; j <= n; j++) solve(c[i],c[j]); sort(inter+1,inter+1+icnt,cmp); double lost=0, left=inter[1].l, right=inter[1].r; for(int j = 2; j <= icnt; j++) { if(inter[j].l>left) { if(inter[j].l>right) { lost+=right-left; left=inter[j].l; right=inter[j].r; } else if(right<inter[j].r)right=inter[j].r; } } if(icnt)lost+=right-left; if(lost<2*pi)ans+=c[i].r*(2*pi-lost); } printf("%.3lf",ans); return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-1123179.html

    最新回复(0)