BUPT Summer Journey #test2 E

时间限制 1000 ms 内存限制 65536 KB

题目描述

木头人星的行动速度是地球上乌龟的 1/10  (所以可以忽略移动的速度),可是他们也热爱运动,尤其是足球。 他们的足球规则跟人类的一样,足球场尺寸为标准 105 * 68,两队各 11 名球员参赛。 假设 Mays 队的每个队员都是专业的球员,踢球都特别准。而她们的对手 Luke 队截球的规律是,如果行进的球离自己的距离不超过 d  ,就可以截球成功。 现在 Mays 队的十号球员拿到了球,如果只允许一次射门,Mays 队能不能进球呢? 足球场在 xy  平面内,(0,0)至(105,68)矩形范围内,边缘与 x,y  轴平行且不能站人。其中Luke队的球门为(0, 30)-(0, 38),Mays 队的球门为(105,30)-(105, 38)

输入格式

第一行为组数 T  ,对这 T  组数据,每组第一行是Mays队十号球员的坐标 x 0 ,y 0   ,接下来 11 行为 Luke 队的 1 - 11 号队员的属性 x i ,y i ,d i   , 其中 x i ,y i   表示 i 号球员的坐标, d i   表示 i  号球员截球能力值。 保证所有坐标不重复且都在球场范围内, x,y  为整数, d  为正实数 1.0d3.0 

输出格式

每组数据一行,如果 Mays 队10号队员直接可以射门得分,则输出“Shoot!‍‍”;如果10号队员不能成功射门,输出"Poor Mays!‍‍".

输入样例

1
104 34
1 24 2.928
48 25 2.605
15 41 1.312
39 42 2.454
3 12 2.080
18 39 1.564
10 36 2.530
97 13 1.589
101 57 1.844
84 39 2.561
0 33 1.831‍

输出样例

Shoot!
思路:一开始想用斜率算。然后转化为斜率的区间覆盖问题。但是存在着很多特判。例如:如果其夹角大于90度的时候它的斜率会变为负,比如他90度的时候又如何算。然后我处理特判的情况又会影响到我一般情况的判断。后来转化成角度问题。以射门10号球员的正下方为0度角,若theta=atan2(Luke[i].y-yo,Luke[i].x-xo)为正,则theta=-theta-90,若theta=atan2(Luke[i].y-yo,Luke[i].x-xo)为负,则theta=270-theta.然后先预处理每个luke球员与10号球员的距离,若小于等于d则会被拦下直接输Poor Mays!若不然再处理每个球员的角度区间[Luke[i].AngleDown,Luke[i].AngleUp],按左端点为关键字即降序排序,然后若球员干扰角度区间[Luke[i].AngleDown,Luke[i].AngleUp]在射门区间[AngleDown,AngleUp]外面不相交则不考虑,若在中间的话若当前的Luke[i].AngleDown大于之间区间合并Luke[i].AngleUp的最大值则存在射门空隙直接break判shoot!否则循环出去后判断它的最大值Luke[i].AngleUp是否超过AngleUp若超过则shoot!若超不过则Poor Mays!

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
//#define LOCAL
using namespace std;
struct point
{
    double x,y,d,AngleUp,AngleDown;
}Luke[20];
struct PP
{
    double x,y;
}UnCovered[20];
const double eps=1e-7;
const double pi=acos(-1.0);
double xo,yo,AngleUp,AngleDown;
int negativecnt;
bool flag;
bool GetLukeAngle(int x)
{
    int i;
    double d=sqrt((xo-Luke[x].x)*(xo-Luke[x].x)+(yo-Luke[x].y)*(yo-Luke[x].y));
    if(abs(Luke[x].d-d)<eps)return false;
    double a=asin(Luke[x].d/d),b;
    double dy=Luke[x].y-yo,dx=Luke[x].x-xo;
    b=atan2(dy,dx);
    if(b>eps)b=3*pi/2-b;
    else if(b<-eps)b=-pi/2-b;
    else b=pi*3/2;
    Luke[x].AngleDown=b-a;
    Luke[x].AngleUp=b+a;
    return true;
}
bool cmp(const point &a,const point &b)
{
    if(abs(a.AngleDown-b.AngleDown)<eps)return a.AngleUp+eps<b.AngleUp;
    return a.AngleDown+eps<b.AngleDown;
}
void Init()
{
    scanf("%lf%lf",&xo,&yo);
    AngleUp=atan2(38.000-yo,-xo);
    if(AngleUp<-eps)AngleUp=-AngleUp-pi/2;
    else if(AngleUp>eps) AngleUp=pi*3/2-AngleUp;
    AngleDown=atan2(30.000-yo,-xo);
    if(AngleDown<-eps)AngleDown=-AngleDown-pi/2;
    else if(AngleDown>eps) AngleDown=pi*3/2-AngleDown;
    flag=true;
    for(int i=1;i<=11;i++)
    {
        scanf("%lf %lf %lf",&Luke[i].x,&Luke[i].y,&Luke[i].d);
        if(flag==true)flag=GetLukeAngle(i);
        else break;
    }
}
void Solve()
{
    sort(Luke+1,Luke+1+11,cmp);
    flag=false;
    double start=AngleDown;
    for(int i=1;i<=11;i++)
    {
            if(Luke[i].AngleUp+eps<AngleDown)continue;
            if(Luke[i].AngleDown>AngleUp+eps)continue;
            if(Luke[i].AngleDown>start+eps)
            {
                flag=true;break;
            }
            else if(Luke[i].AngleUp>start+eps)start=Luke[i].AngleUp;
    }
    if(flag==false&&start+eps<AngleUp)flag=true;
}
int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCAL
    int T;
    scanf("%d",&T);
    while(T--)
    {
        Init();
        if(flag==true)Solve();
        if(flag)printf("Shoot!\n");
        else printf("Poor Mays!\n");
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值