HDU 5572(圆的应用)

HDU 5572

题目 :

An Easy Physics Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Problem Description
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, 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 after some time.

Input
First line contains an integer T, which indicates the number of test cases.
Every test case contains three lines.
The first line contains three integers Ox, Oy and r, indicating the center of cylinder is (Ox,Oy) and its radius is r.
The second line contains four integers Ax, Ay, Vx and Vy, indicating the coordinate of A is (Ax,Ay) and the initial direction vector is (Vx,Vy).
The last line contains two integers Bx and By, indicating the coordinate of point B is (Bx,By).
⋅ 1 ≤ T ≤ 100.
⋅ |Ox|,|Oy|≤ 1000.
⋅ 1 ≤ r ≤ 100.
⋅ |Ax|,|Ay|,|Bx|,|By|≤ 1000.
⋅ |Vx|,|Vy|≤ 1000.
⋅ Vx≠0 or 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 indicates the case number and counts from 1. y is “Yes” if the ball will pass point B after some time, otherwise 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

题意 : 在一个无限光滑的桌面上有一个固定的大圆柱体,还有一个体积忽略不计的小球;开始时静止于A点,给它一个初始速度和方向,如果球撞到圆柱体,他会弹回,没有能量损失;经过一段时间,小球是否会经过B点 ?

思路 : 涉及到直线的表示,圆的表示,点在直线上的投影,点到直线的距离,点对于直线的镜像点,线段和圆的关系,直线和圆的交点等;

先判断射线和圆交点个数,如果小于2再看是否B在A的前进方向上,没有则NO,否则YES。如果等于2,就先找到第一个交点,将这个交点和圆心连成直线,那么A的路径关于这条直线对称,那么如果A关于此直线的对称点在圆心->B路径上,则可以相撞,否则不行。

AC代码 :

https://blog.csdn.net/gpc_123/article/details/122714840

#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); }//放大k倍
    Point operator/(double k) { return Point(x / k, y / k); }//缩小k倍
};
typedef Point Vector;
double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y;}
double vector_length(Vector A) { return sqrt(Dot(A, A));}
double vector_length_square(Vector A) { return Dot(A, A);}
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x;}
double Distance(Point A, Point B) { return hypot(A.x - B.x, A.y - B.y);}
struct Line {
    Point p1, p2;
    Line() {}
    //根据端点确定直线
    Line(Point p1, Point p2) : p1(p1), p2(p2) {}
};
typedef Line Segment;
int Point_line_relation(Point p, Line v) {
    int c = sgn(Cross(p - v.p1, v.p2 - v.p1));
    if (c < 0)return 1;       //1:p在v的左边
    if (c > 0)return 2;       //2:p在v的右边
    return 0;                //0:p在v上
}
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) / vector_length_square(v.p2 - v.p1);
    return v.p1 + (v.p2 - v.p1) * k;
}
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;}
};
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; //线段在圆外
}
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; //直线在圆外
}
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) / vector_length(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);
        //情况一 :直线和圆不相交,而且直线经过点
        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;
            //情况二 :直线和圆相切,不经过点
            if(Line_cross_circle(l,O,pa,pb) != 2)
                printf("Case #%d : NO\n", cas);
            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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值