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

本文介绍了一种算法,用于判断在一个无限光滑平面上,一个小球在特定初始速度及方向下,是否会经过指定位置。该球可在碰撞固定圆柱体后以无能量损失的方式反弹。文章详细展示了输入输出格式,并提供了完整的C++代码实现。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

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 AA, 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 BB after some time.
Input
First line contains an integer TT, which indicates the number of test cases. 

Every test case contains three lines. 

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

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

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

 1 ≤ TT ≤ 100. 

 |OxOx|,|OyOy|≤ 1000. 

 1 ≤ rr ≤ 100. 

 |AxAx|,|AyAy|,|BxBx|,|ByBy|≤ 1000. 

 |VxVx|,|VyVy|≤ 1000. 

 Vx0Vx≠0 or Vy0Vy≠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 xx indicates the case number and counts from 11yy is " Yes" if the ball will pass point BB after some time, otherwise yy 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;
}



开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值