zoukankan      html  css  js  c++  java
  • 洛谷P2510 [HAOI2008]下落的圆盘(计算几何)

    题面

    传送门

    题解

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

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

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

    顺便注意转化为极角的时候如果极角是负的要加上(2pi),如果这时候(l>r),就拆成([l,2pi]+[2pi,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
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    SQL server 日期格式转换style 对应码
    postman的使用方法详解!最全面的教程
    港澳台身份证小结
    使用设置自定义对话框的大小,位置,样式以及设置在安卓桌面上弹出对话框
    android自定义Activity窗口大小(theme运用)
    C#调用RabbitMQ实现消息队列
    C# http请求带请求头部分
    Android如何屏蔽home键和recent键
    针对jquery的优化方法,你知道几条
    试图从目录中执行 CGI、ISAPI 或其他可执行程序
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10513288.html
Copyright © 2011-2022 走看看