codeforces 681E - Runaway to a Shadow 计算几何

来源:互联网 发布:天下3帅气男号捏脸数据 编辑:程序博客网 时间:2024/05/21 17:42

题意: 一只小强速度为v,若在T的时间内不能移动到n个半径为r的圆形掩蔽物的其中一个之下,就会被打死。他的移动策略是随机选一个方向移动,如果进入掩蔽物下就停止移动。问他存活的几率?

分析: 这题的几何意义不难想到,对于其中以小强为圆心的圆,求它与每个遮蔽圆相重叠的角度,最后将所有重叠的角度合并起来除以2*PI就是结果。

要注意判断圆的几种位置关系,相离直接跳过,如果圆心距小于小圆半径答案直接输出1.00000。然后当圆心距<sqrt(R^2+r^2) 此时直接用asin函数算出1/2圆心角,不然的话就是普通的相交,相交用acos加上余弦公式算出1/2圆心角。

每个角度用两个向量来保存,存入一个容器中,注意如果角度跨界了(小于0or大于2*PI)要把一个角度分解成两个。

最后用类似扫描线的算法合并所有角度,所以每个角度的两个向量存入容器时都要附带一个象征起点(终点)的1(-1).

还有就是这题不管如何优化cin,cout都要超时,但是我实在搞不清mingw的long double到底怎么用cstdio的函数输入输出,最终只能输入读成lld再变成long double输出用cout。

AC代码:

#include <iostream>#include <cmath>#include <algorithm>#include <vector>#include <cstdio>#include <iomanip>using namespace std;#define PI 3.1414159265358struct Point {    long double x, y;    Point (long double x=0, long double y=0):x(x),y(y){}};typedef Point Vector;const long double eps =1e-10;int dcmp(long double x){    if(fabs(x)<eps ) return 0;    return x<0?-1:1;}long double Dot(Vector A,Vector B) { return A.x*B.x +A.y*B.y;}long double Length(Vector A){return sqrt(Dot(A,A));}//4.2struct Circle {    Point c;    long double r;    Point  point(long double a) {//极坐标转平面坐标        return Point(c.x +cos(a)*r,c.y+sin(a)*r);    }};long double angle(Vector v) { return atan2(v.y, v.x);}long double X0,Y0,v,T,R;bool flag;vector<pair<long double,int> > vp;void solve(Circle& c){    long double dis=Length(Point(c.c.x-X0,c.c.y-Y0));    if(dcmp(dis-c.r)<=0){ flag=1;return;}    if(dcmp(dis-R-c.r)>0)return;    //计算极角    long double ang0=atan2(c.c.x-X0,c.c.y-Y0);//special    if(dcmp(ang0)<0) ang0+=2*PI;    //计算交点与圆心连线与圆心间连线所成角    long double dd=sqrt(dis*dis-c.r*c.r);    long double ang;    if(dcmp(R-dd)>=0) ang=asin(c.r/dis);    else ang=acos((R*R+dis*dis-c.r*c.r)/(2.0*dis*R));    long double ang1=ang0-ang, ang2=ang0+ang;    if(dcmp(ang1)<0){//分解跨界角        ang1+=2*PI;        vp.push_back(make_pair(ang1,1));        vp.push_back(make_pair(2*PI,-1));        vp.push_back(make_pair(0.0,1));        vp.push_back(make_pair(ang2,-1));    }    else if(dcmp(ang2-2*PI)>0){//ang2与ang1差距不超过PI,故ang1>PI        ang2-=2*PI;        vp.push_back(make_pair(ang1,1));        vp.push_back(make_pair(2*PI,-1));        vp.push_back(make_pair(0.0,1));        vp.push_back(make_pair(ang2,-1));    }    else {        vp.push_back(make_pair(ang1,1));        vp.push_back(make_pair(ang2,-1));    }}int main(){    cin>>X0>>Y0>>v>>T;    R=v*T;    int n;    cin>>n;    flag=0;    while(n--){        Circle c;        int xx,yy,rr;        scanf("%d%d%d",&xx,&yy,&rr);        c.c.x=xx*1.0;        c.c.y=yy*1.0;        c.r=rr*1.0;        solve(c);        if(flag){            cout<<fixed<<setprecision(5)<<1.000<<endl;            return 0;        }    }    sort(vp.begin(),vp.end());    int now=0,last=0,tmp=0;    long double ans=0.0;    for(int i=0;i<vp.size();i++){        now=i;        tmp+=vp[i].second;        if(tmp==0){            ans+=vp[now].first-vp[last].first;            last=now+1;//到now为止构成一个完整的概率区间,下一个起点为now+1.        }    }    cout<<setprecision(5)<<(ans/(2*PI))<<endl;    return 0;}



0 0