hdu 5572 An Easy Physics Problem

传送门;
http://acm.hdu.edu.cn/showproblem.php?pid=5572

上海区域赛铜牌题!!!
令我永生难忘的一道题,当时我们队就是被这道题一直卡着,直接导致最终打铁。。。。当时被气球颜色弄偏了,导致看了一道废题。。。。真的是战略出问题了。

题意:
给出初始点和速度向量,有一个圆,和目标点,可以反弹,问最终能不能碰撞。

计算几何题:
套一下板子,注意讨论就好了,要注意精度误差!!
附上一位某牛的代码,他的板子很值得学习,主要是我之前根本没搞过计算几何~~~

code:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;
const double eps = 1e-8;
const double inf = 1e20;

inline int dcmp(double x) { if (fabs(x) < eps) return 0; return x < 0 ? -1 : 1; }

struct Point {
    double x, y;
    Point (double x = 0, double y = 0): x(x), y(y) {}

    void read() { scanf("%lf%lf", &x, &y); }
    Point operator + (const Point& u) const { return Point(x + u.x, y + u.y); }
    Point operator - (const Point& u) const { return Point(x - u.x, y - u.y); }
    Point operator * (const double& k) const { return Point(x * k, y * k); }
};

typedef Point Vector;

double getCross (Vector a, Vector b) { return a.x * b.y - a.y * b.x; }
double getDot (Vector a, Vector b) { return a.x * b.x + a.y + b.y; }
double getLength(Vector a) { return sqrt(getDot(a, a)); }
Vector getNormal (Vector a) { return Vector(-a.y, a.x); }

struct Circle {
    Point o;
    double r;
    void read() { scanf("%lf%lf%lf", &o.x, &o.y, &r); }
};

int getLineCircleIntersection (Point p, Vector v, Circle O, double& t1, double& t2) {
    double a = v.x, b = p.x - O.o.x, c = v.y, d = p.y - O.o.y;
    double e = a*a+c*c, f = 2*(a*b+c*d), g = b*b+d*d-O.r*O.r;
    double delta = f*f - 4*e*g;
    if (dcmp(delta) < 0) return 0;
    if (dcmp(delta) == 0) {
        t1 = t2 = -f / (2 * e);
        return 1;
    }

    t1 = (-f - sqrt(delta)) / (2 * e);
    t2 = (-f + sqrt(delta)) / (2 * e);
    return 2;
}

bool getIntersection (Point p, Vector v, Point q, Vector w, Point& o) {
    if (dcmp(getCross(v, w)) == 0) return false;
    Vector u = p - q;
    double k = getCross(w, u) / getCross(v, w);
    o = p + v * k;
    return true;
}

Point A, B;
Vector V;
Circle C;

bool onLine (Point a, Vector v, Point b) { return dcmp(getCross(v, b - a)) == 0; }
double getPos(Vector v, Vector t) {
    if (dcmp(v.x) == 0) return t.y / v.y;
    return t.x / v.x;
}

bool judge () {
    double t1, t2, hint = inf;
    int k = getLineCircleIntersection(A, V, C, t1, t2);
    if (k > 1 && dcmp(t1) >= 0) hint = t1;
    else if (k > 1 && dcmp(t2) >= 0) hint = t2;

    if (onLine(A, V, B)) {
        double t = getPos(V, B - A);
        if (dcmp(t) >= 0 && t < hint) return true;
    }

    if (dcmp(hint - inf) < 0) {
        Point I = A + V * hint, T;
        Vector H = getNormal(C.o - I);
        getIntersection(I, H, B, C.o - I, T);
        B = T * 2 - B;

        if (onLine(A, V, B)) {
            double t = getPos(V, B - A);
            if (dcmp(t) >= 0) return true;
        }
    }
    return false;
}

int main () {
    int cas;
    scanf("%d", &cas);
    for (int kcas = 1; kcas <= cas; kcas++) {
        C.read(), A.read(), V.read(), B.read();
        printf("Case #%d: %s\n", kcas, judge() ? "Yes" : "No");
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值