White Bird(AOJ 2308)

本文介绍了一种自动求解《愤怒的小鸟》游戏的算法,重点在于优化白鸟策略,通过抛物线轨迹击中敌人。文章详细解析了如何判断白鸟能否在不碰撞障碍物的情况下投掷蛋炸弹,以及如何枚举所有关键射击角度。
  • 原题如下:

    Angry Birds is a mobile game of a big craze all over the world. You were convinced that it was a waste of time to play the game, so you decided to create an automatic solver.

    You are describing a routine that optimizes the white bird's strategy to defeat a pig (enemy) by hitting an egg bomb. The white bird follows a parabolic trajectory from the initial position, and it can vertically drop egg bombs on the way.

    In order to make it easy to solve, the following conditions hold for the stages.

    • N obstacles are put on the stage.
    • Each obstacle is a rectangle whose sides are parallel to the coordinate axes.
    • The pig is put on the point (X, Y).
    • You can launch the white bird in any direction at an initial velocity V from the origin.
    • If the white bird collides with an obstacle, it becomes unable to drop egg bombs.
    • If the egg bomb collides with an obstacle, the egg bomb is vanished.

    The acceleration of gravity is 9.8 {\rm m/s^2}. Gravity exerts a force on the objects in the decreasing direction of y-coordinate.

    Input

    A dataset follows the format shown below:

    NVXY
    L_1B_1R_1T_1
    ...
    L_NB_NR_NT_N

    All inputs are integer.

    • N: the number of obstacles
    • V: the initial speed of the white bird
    • XY: the position of the pig

    (0 \leq N \leq 500 \leq V \leq 500 \leq X, Y \leq 300X \neq 0)

    for 1 \leq i \leq N,

    • L_i: the x-coordinate of the left side of the i-th obstacle
    • B_i: the y-coordinate of the bottom side of the i-th obstacle
    • R_i: the x-coordinate of the right side of the i-th obstacle
    • T_i: the y-coordinate of the top side of the i-th obstacle

    (0 \leq L_i, B_i, R_i, T_i \leq 300)

    It is guaranteed that the answer remains unaffected by a change of L_iB_iR_i and T_i in 10^{-6}.

    Output

    Yes/No

    You should answer whether the white bird can drop an egg bomb toward the pig.

    Sample Input 1

    0 7 3 1
    

    Output for the Sample Input 1

    Yes
    

    Sample Input 2

    1 7 3 1
    1 1 2 2
    

    Output for the Sample Input 2

    No
    

    Sample Input 3

    1 7 2 2
    0 1 1 2
    

    Output for the Sample Input 3

    No
  • 题解:最后的限制条件常常会在几何问题中附带出现,根据这一点就无需考虑只有通过像穿过针孔一样的唯一线路才能让卵击中猪的情况了。首先,让我们考虑一下如何判断以某个角度射出的鸟是否可以产卵击中猪。只要射出的鸟在撞到障碍物之前能够从猪的正上方飞过,并且此时与猪之间没有障碍物的话,在正上方产卵就可以击中猪了。判断白鸟是否撞到障碍物,就是判断抛物线和长方形是否相交(如果将长方形分解为线段,只判断抛物线是否同各条线段相交,就可能无法很好地处理抛物线恰好经过长方形的顶点的情况)。接下来,思考一下如何枚举所有关键射出角度,假设以某个角度射出时不会遇到障碍物,我们逐渐降低这个角度,直到某出变成
    ① 恰好经过(X,Y)
    ② 恰好经过某个障碍物的左上角或右上角
    就不能再降低了。虽然作为解的角度可能有无穷多个,但因为无论哪个都可以不断降低直至变为1或2的情况,所以只要检查这些角度就足够了。
  • 代码:
     1 #include <cstdio>
     2 #include <cmath>
     3 
     4 using namespace std;
     5 
     6 const double EPS=1e-10;
     7 const int MAX_N=1000;
     8 const double g=9.8;
     9 int N,V,X,Y;
    10 int L[MAX_N], B[MAX_N], R[MAX_N], T[MAX_N];
    11 
    12 double calc(double vy, double t)
    13 {
    14     return vy*t-g*t*t/2;
    15 }
    16 
    17 int cmp(double lb, double ub, double a)
    18 {
    19     return a<lb+EPS ? -1 : a>ub-EPS ? 1 : 0;
    20 }
    21 
    22 bool check(double qx, double qy)
    23 {
    24     double a=g*g/4, b=g*qy-V*V, c=qx*qx+qy*qy;
    25     double D=b*b-4*a*c;
    26     if (D<0 && D>-EPS) D=0;
    27     if (D<0) return false;
    28     for (int d=-1; d<=1; d+=2)
    29     {
    30         double t2=(-b+d*sqrt(D))/(2*a);
    31         if (t2<=0) continue;
    32         double t=sqrt(t2);
    33         double vx=qx/t, vy=(qy+g*t*t/2)/t;
    34         double yt=calc(vy, X/vx);
    35         if (yt<Y-EPS) continue;
    36         bool ok=true;
    37         for (int i=0; i<N; i++)
    38         {
    39             if (L[i]>=X) continue;
    40             if (R[i]==X && Y<=T[i] && B[i]<=yt) ok=false;
    41             int yL=cmp(B[i], T[i], calc(vy, L[i]/vx));
    42             int yR=cmp(B[i], T[i], calc(vy, R[i]/vx));
    43             int xH=cmp(L[i], R[i], vx*(vy/g));
    44             int yH=cmp(B[i], T[i], calc(vy, vy/g));
    45             if (xH==0 && yH>=0 && yL<0) ok=false;
    46             if (yL*yR<=0) ok=false;
    47         }
    48         if (ok) return true;
    49     }
    50     return false;
    51 }
    52 
    53 int min(int x, int y)
    54 {
    55     if (x<y) return x;
    56     return y;
    57 }
    58 
    59 int main()
    60 {
    61     scanf("%d %d %d %d", &N, &V, &X, &Y);
    62     for (int i=0; i<N; i++)
    63     {
    64         scanf("%d %d %d %d", &L[i], &B[i], &R[i], &T[i]);
    65     }
    66     for (int i=0; i<N; i++)
    67     {
    68         R[i]=min(R[i], X);
    69     }
    70     bool ok=check(X,Y);
    71     for (int i=0; i<N; i++)
    72     {
    73         ok |= check(L[i], T[i]);
    74         ok |= check(R[i], T[i]); 
    75     }
    76     puts(ok ? "Yes" : "No");
    77 }

     

转载于:https://www.cnblogs.com/Ymir-TaoMee/p/9791135.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值