链接:http://acm.hdu.edu.cn/showproblem.php?pid=4793
题目大意 :有一个圆硬币半径为r,初始位置为x,y,速度矢量为vx,vy,有一个圆形区域(圆心在原点)半径为R,还有一个圆盘(圆心在原点)半径为Rm (Rm < R),圆盘固定不动,硬币撞到圆盘上会被反弹,不考虑能量损失,求硬币在圆形区域内运动的时间。
运动方程:
x’=x+t*vx;
y’=y+t*vy;
r’=r1+r2;
x’^2+y’^2=r’^2;
解法: 解方程,求 (x+vx*t,y+vy*t) 代入圆形区域方程是否有解,如果没解,说明硬币运动轨迹与圆形区域都不相交,答案为0
如果有解,再看代入圆盘有没有解,如果有解,即为两个解的差值*2, 如果没解,那么就是与圆形区域相交的两个点的t的差值。
难点在于如何构造出两个运动轨迹方程,为什么这么构造。
一共四种情况:
第一种:与外圆相离相切,输出0。
第二种:与外圆相交,与内圆相离相切,输出外圆两个解的差的绝对值。
第三种:与外圆相交,与内圆相交,输出外圆两个解的差的绝对值减去内圆两个解的差的绝对值。
第四种:与外圆相交即有两个解,但是两个解都是负的(要么都是负数要么都是正数),也就是说反向运动才能进入大圆,输出0。
#include<bits/stdc++.h>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define W(t) while(t)
using namespace std;
double eps=1e-10;
int sgn(double x)
{
if(x > eps) return 1;
if(x < -eps) return -1;
return 0;
}
int main()
{
double RM,R,r,x,y,vx,vy;
while(~scanf("%lf%lf%lf%lf%lf%lf%lf",&RM,&R,&r,&x,&y,&vx,&vy))
{
double A1=vx*vx+vy*vy;
double B1=2*x*vx+2*y*vy;
double C1=x*x+y*y-(R+r)*(r+R);
double A2=A1;
double B2=B1;
double C2=x*x+y*y-(RM+r)*(RM+r);
double detla1=B1*B1-4.0*A1*C1;
double detla2=B2*B2-4.0*A2*C2;
double s11=(-B1-sqrt(detla1))/(2.0*A1);
double s12=(-B1+sqrt(detla1))/(2.0*A1);
double s21=(-B2-sqrt(detla2))/(2.0*A2);
double s22=(-B2+sqrt(detla2))/(2.0*A2);
if(sgn(detla1)<=0) //不与圆相交
{
printf("0.000\n");
continue;
}
if(sgn(s12)>=0)
{
if(sgn(detla2)<=0) //只与外面的圆相交
printf("%.3f\n",fabs(s11-s12));
else //与内外两个圆相交
printf("%.3f\n",2*fabs(s21-s11));
}
else //反向
printf("0.000\n");
}
}