• CDOJ 27 棒球防守(baseball) 解题报告


    题目链接http://acm.uestc.edu.cn/#/problem/show/27

    这题是一道数学计算题,比较坑,花了我几天时间

    公式推了挺久的,因为看起来麻烦所以放着几天都懒得做...毕竟暑假

    题目给的变量名太蛋疼了,我这里作新的约定

    防守员的坐标就是((x_0, y_0)),速度(v_0)
    滚地球的速度是(v),沿x轴分速度为(v_x),y轴分速度为(v_y)
    高飞球的落点是((x,y)),飞行时间(t)

    难点在于滚地球,要求是只要某个内场的恰好碰到球或者提前到达轨迹才可以

    不要求在内场碰到,我一开始以为是在内场碰到滚地球

    这样的话题目就变成了求一个某个二次函数在(left[0, frac{r}{sqrt{x^2+y^2}} ight])有没有解的情况

    如果不在内场就简单多了,只要求某个二次函数在([0, +infty))有没有解即可

    先讲高飞球,很简单,计算一下(sqrt{(x-x_0)^2+(y-y_0)^2})和(vt)的关系即可

    这个关系式简单吧,我觉得不需要解释

    然后是滚地球,要使人球能接触,则要求内场防守员跑到球的时间(t)满足以下条件[sqrt{(v_xt-x_0)^2+(v_yt-y_0)^2}le v_0t]

    这是个关于t的二次不等式,我们将两边平方并移项合并,且因为(v_x^2+v_y^2=v^2),得:[(v^2-v_0^2)t^2-2(v_xx_0+v_yy_0)t+(x_0^2+y_0^2)le0]

    很漂亮的不等式,只要这个不等式在(tin [0,infty))有解即可

    当(vge v_0)时,这是显然有解的

    当(v < v_0)时,函数(f(t)=(v^2-v_0^2)t^2-2(v_xx_0+v_yy_0)t+(x_0^2+y_0^2))的对称轴为(t_0=frac{v_xx_0+v_yy_0}{v^2-v_0^2} > 0)

    所以只需要

    [
    egin{align*}
    Delta&=4(v_xx_0+v_yy_0)^2-4(v^2-v_0^2)(x_0^2+y_0^2)\
    &=4(v_x^2x_0^2+v_y^2y_0^2+2v_xv_yx_0y_0-v^2x_0^2-v^2y_0^2+v_0^2x_0^2+v_0^2y_0^2)\
    &=4[v_0^2(x_0^2+y_0^2)-v_y^2x_0^2+2v_xv_yx_0y_0-v_x^2y_0^2]\
    &=4[v_0^2(x_0^2+y_0^2)-(v_yx_0-v_xy_0)^2]geq0
    end{align*}
    ]

    亦即(v_0^2(x_0^2+y_0^2)geq(v_yx_0-v_xy_0)^2)

    所以综上所述,只要一个内场防守员满足(vge v_0)或(v_0^2(x_0^2+y_0^2)geq(v_yx_0-v_xy_0)^2)打击者就out

    所以打成代码如下

    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    #define EPS (1e-8)
    
    int N, M;
    int X[10], Y[10], V[10];
    char ball;
    double XX, YY, T;
    int H, L, VV;
    double vx, vy;
    bool safe;
    
    inline double sqr(double x) {
    	return x * x;
    }
    
    int main() {
    	while (scanf("%d%d", &N, &M) && N && M) {
    		for (int i = 0; i < N; ++i)
    			scanf("%d%d%d", &X[i], &Y[i], &V[i]);
    		while (M--) {
    			safe = true;
    			while ((ball = getchar()) != 'F' && ball != 'G');
    			switch (ball) {
    				case 'G':
    					scanf("%d/%d%d", &H, &L, &VV);
    					vx = VV * L / sqrt(sqr(H) + sqr(L));
    					vy = VV * H / sqrt(sqr(H) + sqr(L));
    					for (int i = 0; i < N; ++i)
    						if (sqr(X[i]) + sqr(Y[i]) < 400)
    							safe &= VV > V[i] && (sqr(X[i]) + sqr(Y[i])) * sqr(V[i]) < sqr(X[i] * vy - Y[i] * vx);
    					break;
    				case 'F':
    					scanf("%lf%lf%lf", &XX, &YY, &T);
    					for (int i = 0; i < N; ++i)
    						safe &= sqr(XX - X[i]) + sqr(YY - Y[i]) > sqr(V[i] * T);
    					break;
    			}
    			if (safe) puts("SAFE"); else puts("OUT");
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    Linux系统操作问题汇总
    记录一些mysql数据库常用操作命令和问题汇总
    python学习之路-练习小程序02(模拟用户登录)
    python学习之路02(基础篇2)
    python学习之路-练习小程序01(猜年龄)
    python学习之路01(基础篇1)
    hashmap详解(基于jdk1.8)
    maven创建项目太慢怎么办
    CAS原理
    JUC原子类3-AtomicLongArray原子类
  • 原文地址:https://www.cnblogs.com/johnsonyip/p/5662156.html
Copyright © 2020-2023  润新知