hdu 5572--An Easy Physics Problem(几何题--圆和射线的交点-直线的对称)

题目大意】:一个面积无限大的光滑桌面,一个质点从初始点A(x0,y0)出发,初速度为(Vx, Vy),桌子上有一个圆柱体,圆心(cx,cy),半径为R,小球如果与圆柱体碰撞则发生的是完全弹性碰撞,在桌子上某处有一点B(ex,ey),问这个质点能不能经过B点?

#include <iostream>
#include <cmath>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int sgn(double x){
    if(fabs(x)<eps)return 0;
    else return x<0?-1:1;
}
struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator+ (Point B){return Point(x+B.x,y+B.y);}
    Point operator- (Point B){return Point(x-B.x,y-B.y);}
    Point operator* (double k){return Point(x*k,y*k);}
    Point operator/ (double k){return Point(x/k,y/k);}
};
double Dot(Point A,Point B){return A.x*B.x+A.y*B.y;}//点积
double Len(Point A){return sqrt(Dot(A,A));}//向量的长度
double len2(Point A){return Dot(A,A);}//向量长度的平方
double Cross(Point A,Point B){return A.x*B.y-A.y*B.x;} //叉积
double Distance(Point A,Point B){return sqrt(pow(A.x-B.x,2)+pow(A.y-B.y,2));}

struct Line{
    Point p1,p2;
    Line(){}
    Line(Point p1,Point p2):p1(p1),p2(p2){}
};
typedef Line Segment;  //定义线段,端点是p1,p2;
int Point_line_relation(Point p,Line v){
    int c=sgn(Cross(p-v.p1,v.p2-v.p1));
    if(c<0)return 1;
    if(c>0)return 2;
    return 0;
}
double Dis_point_line(Point p,Line v){  //点到直线的距离
    return fabs(Cross(p-v.p1,v.p2-v.p1))/Distance(v.p1,v.p2);
}
//点到线段的距离
double Dis_point_seg(Point p,Segment v){
    if(sgn(Dot(p-v.p1,v.p2-v.p1))<0||sgn(Dot(p-v.p2,v.p1-v.p2))<0)
    return min(Distance(p,v.p1),Distance(p,v.p2));
    return Dis_point_line(p,v);
}
//点在直线上的投影
Point Point_line_proj(Point p,Line v){
    double k=Dot(v.p2-v.p1,p-v.p1)/len2(v.p2-v.p1);
    return v.p1+(v.p2-v.p1)*k;
}
//点p对直线v的对称点
Point Point_line_symmetry(Point p,Line v){
    Point q=Point_line_proj(p,v);
    return Point(2*q.x-p.x,2*q.y-p.y);
}
struct Circle{
    Point c;  //圆心
    double r;//半径
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
    Circle(double x,double y,double _r){c=Point(x,y);r=_r;}
};
//线段和圆的关系:0为线段在圆内,1为线段和圆相切,2为线段在圆外
int Seg_circle_relation(Segment v,Circle C){
    double dst=Dis_point_seg(C.c,v);
    if(sgn(dst-C.r)<0)return 0;
    if(sgn(dst-C.r)==0)return 1;
    return 2;
}
//直线和圆的关系:0为直线在圆内,1为直线和圆相切,2为直线在圆外
int Line_circle_relation(Line v,Circle C){
    double dst=Dis_point_line(C.c,v);
    if(sgn(dst-C.r)<0)return 0;
    if(sgn(dst-C.r)==0)return 1;
    return 2;
}
//直线和圆的交点,pa,pb是交点。返回值是交点的个数
int Line_cross_circle(Line v,Circle C,Point &pa,Point &pb){
    if(Line_circle_relation(v,C)==2)return 0;   //无交点
    Point q=Point_line_proj(C.c,v);             //圆心在直线上的的投影
    double d=Dis_point_line(C.c,v);             //圆心到直线的距离
    double k=sqrt(C.r*C.r-d*d);
    if(sgn(k)==0){                              //一个交点,直线和圆相切
        pa=q;pb=q;return 1;
    }
    Point n=(v.p2-v.p1)/Len(v.p2-v.p1);          //单位向量
    pa=q+n*k;
    pb=q-n*k;
    return 2;                                   //俩个交点
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        Circle O;Point A,B,V;
        scanf("%lf%lf%lf",&O.c.x,&O.c.y,&O.r);
        scanf("%lf%lf%lf%lf",&A.x,&A.y,&V.x,&V.y);
        scanf("%lf%lf",&B.x,&B.y);
        Line l(A,A+V);          //射线
        Line t(A,B);
                //情况1:直线和圆不相交,而且直线经过点
        if(Point_line_relation(B,l)==0
        &&Seg_circle_relation(t,O)>=1&&sgn(Cross(B-A,V))==0)
        printf("Case #%d: Yes\n",cas);
        else {
            Point pa,pb;        //直线和圆的交点
            //情况2:直线和圆相切,不经过交点
            if(Line_cross_circle(l,O,pa,pb)!=2){
                printf("Case #%d: No\n",cas);
            }
            //情况3:直线和圆相交
            else {
                Point cut;              //直线和圆的碰撞点
                if(Distance(pa,A)>Distance(pb,A))cut=pb;
                else cut=pa;
                Line mid(cut,O.c);      //圆心到碰撞点的直线
                Point en=Point_line_symmetry(A,mid);//镜像点
                Line light(cut,en);                 //反射线
                if(Distance(light.p2,B)>Distance(light.p1,B)){
                    swap(light.p1,light.p2);
                }
                if(sgn(Cross(light.p2-light.p1,Point(B.x-cut.x,B.y-cut.y)))==0)
                printf("Case #%d: Yes\n",cas);
                else printf("Case #%d: No\n",cas);

            }
        }

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值