HDU 5572 An Easy Physics Problem (计算几何+模板)

On an infinite smooth table, there's a big round fixed cylinder and a little ball whose volume can be ignored. 

Currently the ball stands still at point  A A, then we'll give it an initial speed and a direction. If the ball hits the cylinder, it will bounce back with no energy losses. 

We're just curious about whether the ball will pass point  B B after some time.
Input
First line contains an integer  T T, which indicates the number of test cases. 

Every test case contains three lines. 

The first line contains three integers  Ox Ox Oy Oy and  r r, indicating the center of cylinder is  (Ox,Oy) (Ox,Oy) and its radius is  r r

The second line contains four integers  Ax Ax Ay Ay Vx Vx and  Vy Vy, indicating the coordinate of  A A is  (Ax,Ay) (Ax,Ay) and the initial direction vector is  (Vx,Vy) (Vx,Vy)

The last line contains two integers  Bx Bx and  By By, indicating the coordinate of point  B B is  (Bx,By) (Bx,By)

 1 ≤  T T ≤ 100. 

 | Ox Ox|,| Oy Oy|≤ 1000. 

 1 ≤  r r ≤ 100. 

 | Ax Ax|,| Ay Ay|,| Bx Bx|,| By By|≤ 1000. 

 | Vx Vx|,| Vy Vy|≤ 1000. 

  Vx0 Vx≠0 or  Vy0 Vy≠0

 both A and B are outside of the cylinder and they are not at same position.
Output
For every test case, you should output "  Case #x: y", where  x x indicates the case number and counts from  1 1 y y is "  Yes" if the ball will pass point  B B after some time, otherwise  y y is "  No".
Sample Input
2
0 0 1
2 2 0 1
-1 -1
0 0 1
-1 2 1 -1
1 2
Sample Output
Case #1: No
Case #2: Yes


#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
#define maxn 100005
const double eps = 1e-5;
const double INF = 1e20;
const double pi = acos (-1.0);

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) {}
    bool operator < (const Point &b) const {
        return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
    }
    Point operator + (const Point &b) const {
        return Point (x+b.x, y+b.y);
    }
    Point operator - (const Point &b) const {
        return Point (x-b.x, y-b.y);
    }
    Point operator * (double a) {
        return Point (x*a, y*a);
    }
    Point operator / (double a) {
        return Point (x/a, y/a);
    }
    double len2 () {///返回长度的平方
        return x*x + y*y;
    }
    double len () {///返回长度
        return sqrt (len2 ());
    }
    Point change_len (double r) {///转化为长度为r的向量
        double l = len ();
        if (dcmp (l) == 0) return *this;///零向量返回自身
        r /= l;
        return Point (x*r, y*r);
    }
};

///计算两个向量的叉积
long double cross(const Point &a,const Point &b){
    return a.x*b.y-a.y*b.x;
}
///计算两个点的点积
long double dot(const Point &a,const Point &b){
    return a.x*b.x+a.y*b.y;
}

long double xmult(Point p0,Point p1,Point p2) {///三点构成的两向量的叉积,p0是交点
    return cross((p1-p0),(p2-p0));
}
///dot(p1-p0).(p2-p0)
long double dmult(Point p0,Point p1,Point p2){
    return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);
}
long double dis (Point a, Point b) {///两个点的距离

    Point p = b-a; return p.len ();
}

///************直线 线段
struct Line {
    Point s, e;///直线的两个点
    double k;///极角
    Line () {}
    Line (Point _s, Point _e) {
        s = _s, e = _e;
        k = atan2 (e.y - s.y,e.x - s.x);
    }
    double length () {///求线段长度
        return dis (s, e);
    }
};
///点和直线的关系
int relation (Point p, Line l) {
    ///1:在左侧 2:在右侧 3:在直线上
    int c = dcmp (cross (p-l.s, l.e-l.s));
    if (c < 0) return 1;
    else if (c > 0) return 2;
    else return 3;
}
///判断点在线段上
bool point_on_seg (Point p, Line l) {
    return dcmp (cross (p-l.s, l.e-l.s)) == 0 &&
    dcmp (dot (p-l.s, p-l.e) <= 0);
    ///如果忽略端点交点改成小于号就好了
}
///判断点在射线上
bool point_on_halfline (Point p, Line l) {
    int id = relation (p, l);
    if (id != 3) return 0;
    return dcmp (dot (p-l.s, l.e-l.s)) >= 0;
}

double point_to_line (Point p, Line a) {///点到直线的距离
    return fabs (cross (p-a.s, a.e-a.s) / a.length ());
}

Point projection (Point p, Line a) {///点在直线上的投影
    return a.s + (((a.e-a.s) * dot (a.e-a.s, p-a.s)) / (a.e-a.s).len2() );
}

Point symmetry (Point p, Line a) {///点关于直线的对称点
    Point q = projection (p, a);
    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) {}
};
///直线和圆的关系
int relation (Line a, Circle b) {///直线和圆的交点
    ///0:相离 1:相切 2:相交
    double p = point_to_line (b.p, a);
    if (dcmp (p-b.r) == 0) return 1;
    return (dcmp (p-b.r) < 0 ? 2 : 0);
}

int line_circle_intersection (Line v, Circle u, Point &p1, Point &p2) { ///返回交点个数 交点保存在引用中

    if (!relation (v, u)) return 0;
    Point a = projection (u.p, v);
    double d = point_to_line (u.p, v);
    d = sqrt (u.r*u.r - d*d);
    if (dcmp (d) == 0) {
        p1 = a, p2 = a;
        return 1;
    }
    p1 = a + (v.e-v.s).change_len (d);
    p2 = a - (v.e-v.s).change_len (d);
    return 2;
}

Circle c;
long double vx,vy;
Point a,b;

void solve()
{
    Point aa(a.x+vx,a.y+vy);
    Line Start(a,aa);
    Point jiao1,jiao2;


    int num=line_circle_intersection(Start,c,jiao1,jiao2);
    if(num<2)
    {
        if(dmult(a,aa,b)>eps&&fabs(xmult(a,aa,b))<eps)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    else
    {
        Point jiao;
        if(dis(a,jiao1)>dis(a,jiao2))
            jiao=jiao2;
        else
            jiao=jiao1;
        if(fabs(xmult(jiao,a,b))<eps&&dmult(jiao,a,b)>eps){cout<<"Yes"<<endl;return;}
        Line ojiao(c.p,jiao);
        Point ap=symmetry(a,ojiao);
        if(dmult(jiao,ap,b)>eps&&fabs(xmult(jiao,ap,b))<eps)cout<<"Yes"<<endl;
        else if(dmult(jiao,a,b)>eps&&fabs(xmult(jiao,a,b))<eps&&dis(a,jiao)>dis(a,b))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}
int main ()
 {
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
       cin>>c.p.x>>c.p.y>>c.r;
       cin>>a.x>>a.y>>vx>>vy;
       cin>>b.x>>b.y;
    printf("Case #%d: ",cas);
    solve();
    }

    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值