An Easy Physics Problem HDU-5572 计算几何

An Easy Physics Problem

在这里插入图片描述

solution

对于A构造一条AV,其中保证v足够大即可,判断AV是否与圆相交,分两种情况。
不相交直接判断B是否在AV上,相交则分别考虑B点是否在AV的反射线上或者在AV上

code

/*SiberianSquirrel*/
/*CuteKiloFish*/
#include <bits/stdc++.h>
using namespace std;
#define double long double
const double eps = 1e-8;
const double pi = acos(-1.0);
//`Compares a double to zero`
int sgn(double x) {
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point {
    double x,y;
    Point() {}
    Point(double _x,double _y) {
        x = _x;
        y = _y;
    }
    void input() {
        cin >> x >> y;
    }
    void output() {
        printf("%.2f %.2f\n",x,y);
    }
    bool operator == (Point b)const {
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    bool operator < (Point b)const {
        return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;
    }
    Point operator -(const Point &b)const {
        return Point(x-b.x,y-b.y);
    }
    double operator ^(const Point &b)const {//叉积
        return x*b.y - y*b.x;
    }
    double operator *(const Point &b)const {//点积
        return x*b.x + y*b.y;
    }
    double len() {//返回长度
        return hypot(x,y);//库函数
    }
    double len2() {	//返回长度的平方
        return x*x + y*y;
    }
    double distance(Point p) {	//返回两点的距离
        return hypot(x-p.x,y-p.y);
    }
    Point operator +(const Point &b)const {
        return Point(x+b.x,y+b.y);
    }
    Point operator *(const double &k)const {
        return Point(x*k,y*k);
    }
    Point operator /(const double &k)const {
        return Point(x/k,y/k);
    }
    //`化为长度为r的向量`
    Point trunc(double r) {
        double l = len();
        if(!sgn(l))return *this;
        r /= l;
        return Point(x*r,y*r);
    }
};

struct Line {
    Point s,e;
    Line() {}
    Line(Point _s,Point _e) {
        s = _s;
        e = _e;
    }
    bool operator ==(Line v) {
        return (s == v.s)&&(e == v.e);
    }
    //`根据一个点和倾斜角angle确定直线,0<=angle<pi`
    //ax+by+c=0
    Line(double a,double b,double c) {
        if(sgn(a) == 0) {
            s = Point(0,-c/b);
            e = Point(1,-c/b);
        } else if(sgn(b) == 0) {
            s = Point(-c/a,0);
            e = Point(-c/a,1);
        } else {
            s = Point(0,-c/b);
            e = Point(1,(-c-a)/b);
        }
    }
    void input() {
        s.input();
        e.input();
    }
    //求线段长度
    double length() {
        return s.distance(e);
    }
    //`点和直线关系`
    //`1  在左侧`
    //`2  在右侧`
    //`3  在直线上`
    int relation(Point p) {
        int c = sgn((p-s)^(e-s));
        if(c < 0)return 1;
        else if(c > 0)return 2;
        else return 3;
    }
    // 点在线段上的判断
    bool pointonseg(Point p) {
        return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
    }
    //`两向量平行(对应直线平行或重合)`
    bool parallel(Line v) {
        return sgn((e-s)^(v.e-v.s)) == 0;
    }
    //`求两直线的交点`
    //`要保证两直线不平行或重合`
    Point crosspoint(Line v) {
        double a1 = (v.e-v.s)^(s-v.s);
        double a2 = (v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
    //点到直线的距离
    double dispointtoline(Point p) {
        return fabs((p-s)^(e-s))/length();
    }
    //点到线段的距离
    double dispointtoseg(Point p) {
        if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
            return min(p.distance(s),p.distance(e));
        return dispointtoline(p);
    }
    //`返回点p在直线上的投影`
    Point lineprog(Point p) {
        return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
    }
    //`返回点p关于直线的对称点`
    Point symmetrypoint(Point p) {
        Point q = lineprog(p);
        return Point(2*q.x-p.x,2*q.y-p.y);
    }
};
//圆
struct circle {
    Point p;//圆心
    double r;//半径
    circle() {}
    circle(Point _p,double _r) {
        p = _p;
        r = _r;
    }
    circle(double x,double y,double _r) {
        p = Point(x,y);
        r = _r;
    }
    void input() {//输入
        p.input();
        cin >> r;
        //        scanf("%lf",&r);
    }
    void output() {//输出
        printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r);
    }
    bool operator == (circle v) {
        return (p==v.p) && sgn(r-v.r)==0;
    }
    bool operator < (circle v)const {
        return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));
    }
    int relationseg(Line v) {
        double dst = v.dispointtoseg(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r) == 0)return 1;
        return 0;
    }
    int relationline(Line v) {
        double dst = v.dispointtoline(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r) == 0)return 1;
        return 0;
    }
    int pointcrossline(Line v,Point &p1,Point &p2) {
        if(!(*this).relationline(v))return 0;
        Point a = v.lineprog(p);
        double d = v.dispointtoline(p);
        d = sqrt(r*r-d*d);
        if(sgn(d) == 0) {
            p1 = a;
            p2 = a;
            return 1;
        }
        p1 = a + (v.e-v.s).trunc(d);
        p2 = a - (v.e-v.s).trunc(d);
        return 2;
    }
};

Point a, b, v;
circle o;
double vx, vy;
void solve() {
    int _, cases = 0;
    cin >> _;
    while(_ --) {
        bool f = false;
        o.input();
        a.input();
        v.input();
        b.input();

        Line av(a, a + v * 10000);

        if (o.relationseg(av) == 2) {
            //A会碰到圆
            Point p1, p2;
            o.pointcrossline(av, p1, p2);
            Line op(p2, o.p);
            Point _a = op.symmetrypoint(a);
            Line pa(p2, a);
            Line p_a(p2, p2 + (_a - p2) * 10000);
            if (p_a.pointonseg(b) || pa.pointonseg(b)) f = true;
        } else {
            //A不会碰到圆
            if (av.pointonseg(b)) f = true;
            else f = false;
        }

        cout << "Case #" << ++ cases << ": ";
        if(f) cout << "Yes" << endl;
        else cout << "No" << endl;
    }

}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值