aoj2308(#离散化,极限情况)

/*
translation:
    可以从任意方向以速度v发射一只白鸟,可在任意时刻产下一枚卵。发射后鸟将以抛物线轨迹飞行。空中有若干障碍物,问鸟
    产下的卵是否能击中目标(x,y)
solution:
    极限情况的离散化
note:
    * 考虑到鸟的飞行轨迹是无数种方案的,所以只需考虑其中的极限情况,即擦着障碍物的边飞过去。所以可以枚举飞行轨迹
      经过的点,也就是每个障碍的左上和右上2个顶点,之后求出飞行轨迹。判断是否经过其它的障碍物。
    # 思路简单,但是编码麻烦,考虑的各种情况比较繁多。
*/
#include <iostream>
#include <cmath>
#include <cstdio>

using namespace std;
const int maxn = 100;
const double g = 9.8;
const double EPS = 1e-10;

int n, v, X, Y;
int L[maxn], B[maxn], R[maxn], T[maxn];

void solve_equation(double x, double y, double& vx0, double& vy0, double& vx1, double& vy1)
{
    double a = g * g / 4, b = g * y - v * v, c = x * x + y * y;
    double D = b * b - 4 * a * c;
    if(D < 0 && D > -EPS)   D = 0;
    if(D < 0) {
        vx0 = vx1 = -1;
        vy0 = vy1 = -1;
        return;
    }
    double t20 = (-b + sqrt(D)) / (2 * a), t21 = (-b - sqrt(D)) / (2 * a);
    if(t20 <= 0) {
        vx0 = vy0 = -1;
        return;
    }
    double t0 = sqrt(t20);
    vx0 = x / t0;
    vy0 = (y + g * t0 * t0 / 2) / t0;

    if(t21 <= 0) {
        vx1 = vy1 = -1;
        return;
    }
    double t1 = sqrt(t21);
    vx1 = x / t1;
    vy1 = (y + g * t1 * t1 / 2) / t1;
}

double calculate_y(double vy, double t)
{
    return vy * t - g * t * t / 2;
}

int cmp(double lb, double ub, double a)
{
    return a < lb + EPS ? -1 : a > ub - EPS ? 1 : 0;
}

bool check(double x, double y) //检查抛物线经过点x,y时是否能够满足要求
{
    double vx[2], vy[2];   //根据抛物线求出水平方向和垂直方向的速度
    solve_equation(x, y, vx[0], vy[0], vx[1], vy[1]);

    for(int i = 0; i < 2; i++) {
        if(vx[i] < 0 || vy[i] < 0)  continue;   //解是否有意义
        if(calculate_y(vy[i], X / vx[i]) < Y - EPS) continue; //抛物线是否可行

        //检测抛物线途中是否有障碍物
        bool has_obstacle = false;
        for(int j = 0; j < n; j++) {
            if(L[j] >= X)   continue;
            if(R[j] == X && Y <= T[j] && calculate_y(vy[i], X / vx[i]) >= B[j]) has_obstacle = true;

            int yl = cmp(B[j], T[j], calculate_y(vy[i], (double)L[j] / vx[i]));
            int yr = cmp(B[j], T[j], calculate_y(vy[i], (double)R[j] / vx[i]));
            int xh = cmp(L[j], R[j], vx[i] * (vy[i] / g));
            int yh = cmp(B[j], T[j], calculate_y(vy[i], vy[i] / g));
            if(yl * yr <= 0)    has_obstacle = true;
            if(xh == 0 && yh >= 0 && yl < 0)    has_obstacle = true;
        }
        if(!has_obstacle)   return true;
    }
    return false;
}

bool solve()
{
    for(int i = 0; i < n; i++)  R[i] = min(X, R[i]);

    if(check(X, Y)) return true;
    for(int i = 0; i < n; i++) {
        if(check(L[i], T[i]) || check(R[i], T[i]))
            return true;
    }
    return false;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(cin >> n >> v >> X >> Y) {
        for(int i = 0; i < n; i++) {
            cin >> L[i] >> B[i] >> R[i] >> T[i];
        }

        if(solve()) printf("Yes\n");
        else        printf("No\n");
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值