TopCoder SRM 323 Div1 Medium Survived

問題

x,y平面上の原点に人がいる。
原点から、点(x,y)へ泳いで行きたい。
この人の泳ぐ速さは最大でVである。


水は、x軸の正の向きに、一様で速度Uで流れている。


この人が(x,y)まで着くのにかかる時間を求めよ。
(x,y)に辿り着けない場合は-1を返せ。

制約条件

-100≦x,y≦100
0≦U,V≦100

方針

流れのない状態で、泳ぐ向きの角をtとする。
流れがない状態では泳ぎの速度のベクトルは(Vcos(t),Vsin(t) )
流れがある状態での速度のベクトルは(Vcos(t)+U,Vsin(t) )


このベクトルが(x,y)に平行になればよいので、
Vxsin(t)=Vycos(t)+yU
ここから、三角関数の合成を使って、√(x^2+y^2) sin(t-α)=yU/V
ただしαはtanα=y/xを満たす角
となって、tが求まる。


tが求まれば、速度ベクトルが求まり、目的地までの時間がもとまる。


上の方程式が解をもたない場合や、
速度ベクトルと(x,y)のベクトルが反平行になった場合は、辿り着くことができない。


コーナーケースが多すぎて通すの大変だった。

ソースコード

double sq(double x){
	return x*x;
}

class Survived {
	public:
	double minTime(int x, int y, int V, int U) 
	{
		if(x*x+y*y==0)return 0;
		
		double a=sq(V*x)+sq(V*y);
		if(V==0&&y*U==0){
			if(U==0||y!=0||x<0)return -1;
			return x*1.0/U;
		}
		if(a<sq(y*U))return -1;
		
		double t=asin(y*U/sqrt(a))+atan2(y,x);
		double dy=V*sin(t), dx=V*cos(t)+U;
		
		if(x*dx+y*dy<EPS)return -1;
		return hypot(x,y)/hypot(dy,dx);
	}
};