HDU-5527 An Easy Physics Problem(平面上点到圆碰撞反弹)

题目:给一个圆和圆外两点A、B,A以给定的速度出发,若碰到圆则发生完全弹性碰撞,问能否经过B。

思路:分类讨论1:A的路径碰到了圆,找出两条射线判断是否经过B点。2:A的路径没有碰到了圆,判断一条射线是否经过B点。

精度是真的麻烦。。

#include<bits/stdc++.h>
using namespace std;
typedef long double ldouble;
const ldouble eps = 1e-8;
const ldouble inf = 1e20;
const ldouble pi = acos(-1.0);
const int maxp = 1010;
int sgn(ldouble x){
    if(fabs(x) < eps)return 0;
    if(x < 0)return-1;
    else return 1;
}
inline ldouble sqr(ldouble x){return x*x;}
struct Point{
    ldouble x,y;
Point(){}
    Point(ldouble _x,ldouble _y){
        x = _x;
        y = _y;
    }
    void input(){
        scanf("%lf%lf",&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);
    }
    //叉积
    ldouble operator ^(const Point &b)const{
        return x*b.y-y*b.x;
    }
    //点积
    ldouble operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
    //返回长度
    ldouble len(){
        return hypot(x,y);//库函数
    }
    //返回长度的平方
    ldouble len2(){
        return x*x + y*y;
    }
    //返回两点的距离
    ldouble 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 ldouble &k)const{
        return Point(x*k,y*k);
    }
    Point operator /(const ldouble &k)const{
        return Point(x/k,y/k);
    }
    //化为长度为 r 的向量
    Point trunc(ldouble r){
        ldouble 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);
    }
    //求线段长度
    ldouble length(){
        return s.distance(e);
    }
    // 点在线段上的判断
    bool pointonseg(Point p){
        return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
    }
    //点到直线的距离
    ldouble dispointtoline(Point p){
        return fabs((p-s)^(e-s))/length();
    }
    //点到线段的距离
    ldouble 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;//圆心
    ldouble r;//半径
circle(){}
    circle(Point _p,ldouble _r){
        p = _p;
        r = _r;
    }
    circle(ldouble x,ldouble y,ldouble _r){
        p = Point(x,y);
        r = _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 relationline(Line v){
        ldouble 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);
        ldouble 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 pa,pb,c;
Line l1,l2,l0;
circle cc;
ldouble dx,dy,r;
int main()
{
   // freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    int cas=0;
    while(t--)
    {
        int flag=0;
        //scanf("%lf%lf%lf",&c.x,&c.y,&r);
        cin>>c.x>>c.y>>r;
        //scanf("%lf%lf%lf%lf",&pa.x,&pa.y,&dx,&dy);
        cin>>pa.x>>pa.y>>dx>>dy;
        //scanf("%lf%lf",&pb.x,&pb.y);
        cin>>pb.x>>pb.y;
        pa.x-=c.x;pa.y-=c.y;
        pb.x-=c.x;pb.y-=c.y;
        c.x=c.y=0;
        l0.s=pa;
        l0.e.x=pa.x+dx*10000; l0.e.y=pa.y+dy*10000;
        cc.p.x=c.x,cc.p.y=c.y,cc.r=r;
        Point p1,p2;
        int tmp=cc.pointcrossline(l0,p1,p2);
        Point ap;
        ap.x=pa.x+dx*0.001; ap.y=pa.y+dy*0.001;
        if(tmp==2&&ap.x*ap.x+ap.y*ap.y<pa.x*pa.x+pa.y*pa.y)
        {
            if(sgn(pa.distance(p1)-pa.distance(p2))>0)
                swap(p1,p2);
            l1.s=pa,l1.e=p1;
            Line lk;
            lk.s=c,lk.e=p1;
            pa.x-=10000*dx; pa.y-=10000*dy;
            Point paa=lk.symmetrypoint(pa);
            l2.s=p1;l2.e=paa;
            if(l1.pointonseg(pb)||l2.pointonseg(pb))
                flag=1;
        }
        else
        if(l0.pointonseg(pb))
                flag=1;
        if(flag)
            printf("Case #%d: Yes\n",++cas);
        else
            printf("Case #%d: No\n",++cas);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/82353967