Codeforces Round #357 (Div. 2) E 计算几何

传说中做cf不补题等于没做 于是第一次补...这次的cf没有做出来DE D题的描述神奇 到现在也没有看懂 于是只补了E 

每次div2都是hack前2~3题 终于打出一次hack后的三题了...希望以后能越来越好 早日..至少变成蓝色名字吧:)

E题意 有一个蟑螂 人要打死它 给出蟑螂的坐标 速度 人的瞄准时间 再给出一些阴影(圆形且给出坐标与半径) 若蟑螂移动到阴影内会立即停下 人不能打到阴影中的蟑螂 问它不被打死的机率 蟑螂的移动方向是随机的

需要注意的是蟑螂只会朝一个方向走直线

所以我们对于每一个阴影圆 都判断一次 能否走到 如果能走到 就计算角度 这里利用atan来实现 atan(x,y) 返回的是平面直角坐标系上原点到x,y的线与x轴的夹角

需要注意的是 在两个圆的相交到一定程度的时候需要进行判断 是否到了最大值 在到达最大值之后 角度会减小 这时候应当取最大的角度 

对于每一个可以到达的阴影 我们都可以得出一个角度区间 最后我们应当对每个区间进行合并 

在angle+-ang之后 可能产生<-pi or >pi的角度 这时候我们进行分割 分成两份 一份在最左 一份在最右

排个序再进行判断就好

在补这道题的时候 acos的时候写错了字母...一路跑到了test79才wa掉...真是..doubility

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<iostream>
#include<queue>
using namespace std;
double x0,yy,v,t;
int n;
double pi;
struct node
{
    double x,y,r;
};
node a[100050];
int w;
struct no
{
    double k1,k2;
};
no b[100050];
double dis(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double r;
void check(int x){
    if(dis(a[x].x,a[x].y,x0,yy)>=(r+a[x].r))
        return ;
    double d=dis(a[x].x,a[x].y,x0,yy);
    /// -pi<angel<pi
    double angle=atan2(a[x].x-x0,a[x].y-yy);
    double r1=sqrt(d*d-a[x].r*a[x].r);
    double ang;
    if(r1<r){
        ang=asin(a[x].r/d);
    }
    else {
        ang=acos((d*d+r*r-a[x].r*a[x].r)/(2*d*r));
    }
    double al=angle-ang;
    double ar=angle+ang;
    if(al>=-pi-0.000000000001&&ar<=pi+0.000000000001){
        w++;
        b[w].k1=al;
        b[w].k2=ar;
    }
    else if(al<-pi-0.000000000001){
        w++;
        b[w].k1=-pi;
        b[w].k2=ar;
        w++;
        b[w].k1=pi+(al+pi);
        b[w].k2=pi;
    }
    else if(ar>pi+0.000000000001){
        w++;
        b[w].k1=al;
        b[w].k2=pi;
        w++;
        b[w].k1=-pi;
        b[w].k2=-pi+(ar-pi);
    }
    return ;
}
int cmp(no a,no b){
    return a.k1<b.k1;
    return a.k2>b.k2;
}
int main(){
while(cin>>x0>>yy>>v>>t){
    pi=acos(-1);
    cin>>n;
    bool ok=false;
    for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].r);
        if((x0-a[i].x)*(x0-a[i].x)+(yy-a[i].y)*(yy-a[i].y)<=a[i].r*a[i].r){
            ok=true;
        }
    }
    r=v*t;
    if(ok==true){
        printf("1.00000000000\n");
    }
    else {
        w=0;
        for(int i=1;i<=n;i++){
            check(i);
        }
        if(w==0)
        {
            printf("0.00000000000\n");
        }
        else {
            sort(b+1,b+1+w,cmp);
            double ans=0;
            double q=-pi;
            for(int i=1;i<=w;i++)
            {
                double l=b[i].k1;
                double r=b[i].k2;
                if(r>q){
                    double ll;
                    if(l>q){
                        ll=l;
                    }
                    else {
                        ll=q;
                    }
                    if(r-ll>0)
                    ans+=(r-ll);
                    q=r;
                }
                else continue;
            }
            printf("%.11f\n",ans/(2*pi));
        }
    }

}
}

  

转载于:https://www.cnblogs.com/rayrayrainrain/p/5592043.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值