ZOJ 3728 Collision 简单几何

        在平面上0,0点,有一个半径为R的圆形区域,并且在0,0点固定着一个半径为RM(<R)的圆形障碍物,现在圆形区域外x,y,有一个半径为r的,并且速度为vx,vy的硬币,如果硬币碰到了障碍物,将会保持原有的速度向反射的方向继续前进,现在给出R,RM,r,x,y,vx,vy,问硬币的任意部分在圆形区域中滑行多少时间?

        首先把R,RM加上r,就可以把硬币看做一个点来讨论了,然后算一下射线与这两个圆交点的个数,记作C1,C2,CM1,CM2,若与两个圆的交点数都是2,答案就是dis(c1,c2)-dis(cm1,cm2)之后再除以合成后的速度,若与大圆的交点数为2,小圆的交点数是0或者1,答案就是dis(c1,c2)/合成后的速度,否则肯定是0了.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;

int dcmp(double x) { return (x>eps)-(x<-eps);}

typedef struct Point
{
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y){}
    Point operator+(const Point& p) const { return Point(x+p.x, y+p.y );}
    Point operator-(const Point& p) const { return Point(x-p.x, y-p.y );}
    Point operator*(const double d) const { return Point(x*d, y*d );}
    Point operator/(const double d) const { return Point(x/d, y/d );}
    void read() { scanf("%lf%lf", &x, &y);}
}Vector;

inline double Dis(const Point& a, const Point& b)
{
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

struct Line
{
    Point P;
    Vector v;
    double ang;
    Line(){}
    Line(const Point& P, const Vector& v):P(P),v(v){ang = atan2(v.y,v.x);}
    bool operator<(const Line& L) const
    {
        return ang<L.ang;
    }
    Point point(double t)
    {
        return P+v*t;
    }
};

struct Circle
{
    Point c;
    double r;
    Circle(){}
};

int GetLineCircleIntersection(Line L, Circle C, double &t1, double &t2, vector<Point> &sol)
{
    double a = L.v.x, b = L.P.x-C.c.x, c = L.v.y, d = L.P.y - C.c.y;
    double e = a*a+c*c, f = 2*(a*b+c*d), g = b*b+d*d-C.r*C.r;
    double delta = f*f-4*e*g;
    if(dcmp(delta)<0) return 0;
    if(dcmp(delta)==0)
    {
        t1 = t2 = -f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }
    t1 = (-f-sqrt(delta))/(2*e);sol.push_back(L.point(t1));
    t2 = (-f+sqrt(delta))/(2*e);sol.push_back(L.point(t2));
    if(dcmp(t1)<0 || dcmp(t2)<0) return 0;
    return 2;
}

double R,RM,r,x,y,vx,vy;
int n,m,k;

int main()
{
//    freopen("in.txt","r",stdin);
    while(~scanf("%lf%lf%lf%lf%lf%lf%lf",&RM,&R,&r,&x,&y,&vx,&vy))
    {
        Line l1(Point(x,y),Point(vx,vy));
        Circle c1,c2;
        c1.r=RM+r;
        c1.c.x=c1.c.y=0.0;
        c2.c.x=c2.c.y=0.0;
        c2.r=R+r;
        double db1=0.0,db2=0.0;
        vector<Point> crs1;
        vector<Point> crs2;
        int num2=GetLineCircleIntersection(l1,c1,db1,db2,crs2);
        int num1=GetLineCircleIntersection(l1,c2,db1,db2,crs1);
        double len=0.0,ans=0.0;
        double vv=sqrt(vx*vx+vy*vy);
        if (num1==2 && num2==2)
        {
            len=Dis(crs1[0],crs1[1])-Dis(crs2[0],crs2[1]);
            printf("%.4lf\n",len/vv);
        }
        else
        if (num1==2)
        {
            len=Dis(crs1[0],crs1[1]);
            printf("%.4lf\n",len/vv);
        }
        else
        {
            puts("0.0000");
        }
    }
    return 0;
}


       

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值