ZOJ 3728 Collision

题目大意

        有一个圆形奖章固定在一个光滑桌面,我们抛出一些硬币,让它们朝着奖章碰撞。还有一个圆形范围内,圆形范围与奖章有同样的圆心,圆形奖章严格小于圆形范围半径。假设硬币碰撞奖章时不损失能量,然后镜面反射移动方向。 

        假设圆奖牌和圆范围的圆心是(0,0),硬币的初始位置是严格在圆外的。奖章半径Rm,硬币半径r,则圆范围半径R,初始位置(x,y)和初始速度矢量硬币(Vx,Vy)的半径。请计算硬币的任意部分在圆形范围内的总时间。


【分析】

(吐槽:翻译好累啊。。。。)

题目其实很简单,我们可以简单分为三种情况。

1.硬币不进入范围,输出0;

2.硬币进入范围,与奖章碰撞

3.进入范围,不碰撞

只要确定了是哪种情况,剩余的在草稿纸上画画就可以得到答案了。

区分1与2.3时。我们令点P为硬币的圆心,令Q=P+1000*V,于是Q便是P走了1000个单位时间的位置。

我们判断Vector(OP) Dot Vector(QP) 的正负,如果非正,那么为情况1。

我们求得点O(0,0)与直线VP的距离为OVP。如果OVP>(R+r),那么同样不进入范围,为情况1.

区分2与3时。如果OVP>(Rm+r),为情况3,否则为情况2.

剩下的就用勾股定理即可解决。


【代码】

/***********************
    ID:Ciocio
	LANG:C++
	DATE:2014-1-21
	TASK:Collision
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define sqr(x) ((x)*(x))

double Rm,R,r;
struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Point P;
Point O=Point(0,0);
Vector V;
Vector operator + (Vector A,Vector B)
{return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Point A,Point B)
{return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p)
{return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p)
{return Vector(A.x/p,A.y/p);}
bool operator < (const Point &a,const Point &b)
{return a.x<b.x||(a.x==b.x&&a.y<b.y);}
const double eps=1e-10;
int dcmp(double x){if(fabs(x)<eps) return 0;else return x<0?-1:1;}
bool operator == (const Point &a,const Point &b)
{return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
double Dot(Vector A,Vector B)
{return A.x*B.x+A.y*B.y;}
double Cross(Vector A,Vector B)
{return A.x*B.y-A.y*B.x;}
double Length(Vector A){return sqrt(Dot(A,A));}
Vector Normal(Vector A)
{double L=Length(A);
return Vector(-A.y/L,A.x/L);}
double Dis(Point A,Point B)
{return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));}


void _init()
{
	scanf("%lf%lf",&P.x,&P.y);
	scanf("%lf%lf",&V.x,&V.y);
}

void _solve()
{
	Vector Q=P+Vector(V.x*1000,V.y*1000);
	if(Dot(P-Q,P-O)<=0)   //OP.QP
	{
		printf("0.000\n");
		return;
	}
	double OVP=fabs(Cross(P-Q,P-O)/Length(P-Q));   //the distance of point O and line VP
	double len1=sqrt(sqr(R+r)-sqr(OVP));
	double len2=len1-(sqrt(sqr(Rm+r)-sqr(OVP)));
	if(OVP>(R+r))                   //if the coin is not going through the range
	{
		printf("0.000\n");
		return;
	}
    if(OVP>(Rm+r)) printf("%.3lf\n",2*len1/Length(V));    //not impact
	else printf("%.3lf\n",2*len2/Length(V));            //impact
}

int main()
{
    while(scanf("%lf%lf%lf",&Rm,&R,&r)!=EOF)
    {
	    _init();
	    _solve();
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值