2015ACM/ICPC亚洲区上海站 An Easy Physics Problem

An Easy Physics Problem

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1151 Accepted Submission(s): 195

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

链接 http://acm.hdu.edu.cn/showproblem.php?pid=5572

题意

给一个点a和它前进的方向,地图上还有一个圆柱,a撞到圆柱会反弹,问a会不会经过b点

思路

撞上之后沿那一点的切线反弹,几何关系很明显

代码

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
double eq=1e-6;
struct point
{
    double x,y;
}o,a,b,v,d,t;

//a,b两点间距离的平方 
double len_2(struct point a,struct point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}

//a,b两点间距离
double len(struct point a,struct point b)
{
    return sqrt(len_2(a,b));
}

//向量ab,ac的内积 
double dot(struct point a,struct point b,struct point c)
{
    return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)+(c.y-a.y);
}

//向量ab叉乘ac的值 
double cross(struct point a,struct point b,struct point c)
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

//点p到直线Ax+By+C=0的距离的平方
double dis_2(struct point p,double A,double B,double C)
{
    return (A*p.x+B*p.y+C)*(A*p.x+B*p.y+C)/(A*A+B*B);
}

//点p到直线Ax+By+C=0的距离
double dis(struct point p,double A,double B,double C)
{
    return abs(A*p.x+B*p.y+C)/sqrt(A*A+B*B);
}


//已知向量ab与ac平行,判断是否同向
bool same_direction(struct point a,struct point b,struct point c)
{
    b.x-=a.x;
    b.y-=a.y;
    c.x-=a.x;
    c.y-=a.y;
    if (abs(b.x-c.x)<eq)
    {
        if ( abs(b.y-c.y)<eq || (b.y>eq && c.y>eq) || (b.y<-eq && c.y<-eq) ) return true;
        else return false;
    }
    else
    {
        if ( (b.x>eq && c.x>eq) || (b.x<-eq && c.x<-eq) ) return true;
        else return false;
    }
} 

//直线Ax+By+C=0上距离点p最近的点 
struct point closest_point(struct point p,double A,double B,double C)
{
    struct point q;
    q.x=(B*B*p.x-A*B*p.y-A*C)/(A*A+B*B);
    q.y=(A*A*p.y-A*B*p.x-B*C)/(A*A+B*B);
    return q;
}

//点p关于直线Ax+By+C=0的对称点 
struct point symmetric_point(struct point p,double A,double B,double C)
{
    struct point q;
    q.x=2*closest_point(p,A,B,C).x-p.x;
    q.y=2*closest_point(p,A,B,C).y-p.y;
    return q;
}

//已知a,b,p共线,p是否在线段ab上 
bool P_in_AB(struct point p,struct point a,struct point b)
{
    if ( len_2(a,p)-len_2(a,b)<eq ) return true;
    else return false;
}

int main()
{
    int T,ans;
    scanf("%d",&T);
    double r;
    for (int kase=1;kase<=T;kase++)
    {
        ans=0;
        scanf("%lf %lf %lf",&o.x,&o.y,&r);
        scanf("%lf %lf %lf %lf",&a.x,&a.y,&v.x,&v.y);
        scanf("%lf %lf",&b.x,&b.y);


        double l=dis(o,v.y,-v.x,a.y*v.x-a.x*v.y);
        double l_2=dis_2(o,v.y,-v.x,a.y*v.x-a.x*v.y);
        t.x=a.x+v.x;
        t.y=a.y+v.y;//t为直线上另一点 
        if ( l-r<-eq ) 
        {
            double ad=sqrt(len_2(a,o)-l_2)-sqrt(r*r-l_2);
            double lv=sqrt(v.x*v.x+v.y*v.y);
            d.x=a.x+v.x*ad/lv;
            d.y=a.y+v.y*ad/lv;//交点 

            if (same_direction(a,t,d) || ( abs(a.x-d.x)<eq&&abs(a.y-d.y)<eq&&dot(a,o,t)>eq ) )//会撞上 
            {
                //碰撞前
                if (abs(cross(a,t,b))<eq&&same_direction(a,t,b)&&P_in_AB(b,a,d)) ans=1;
                b=symmetric_point(b,-(d.x-o.x),(o.y-d.y),d.x*(d.x-o.x)-d.y*(o.y-d.y));
            }
        }
        if (abs(cross(a,t,b))<eq) //共线 
        {
            if (same_direction(a,t,b)) ans=1;
        }


        if (ans) printf("Case #%d: Yes\n",kase);
        else printf("Case #%d: No\n",kase);

    }
    return 0;
}

PS

一上来写的姿势不太对,导致写了两个晚上。。不过也好。。自己手写了一些几何的板子出来。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值