HDU 5027 Help! (Intersection of three + circles and line segments), hdu5027
Help!Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission (s): 180 Accepted Submission (s): 32
Problem Description "Help! Help !"
While walking in the park, you suddenly hear someone shouting for help. You immediately realize that a person has fallen into the lake. As a brave man, you decide to save him.
You are really familiar with the terrain of the park. the park can be regarded as a 2D plane. and the lake is a convex polygon. at current, you are on (Xo, Yo), and the person is on (Xp, Yp ). you also know that you can run Vr per second on the land, or swim Vs per second in the lake. notice that you are allowed to run along the edge of the lake.
You are not good at swimming. You cannot stay in the lake longer than Ts second. And carrying another person will cut down your swimming speed by half.
Can you save the poor guy? What is the minimum time for you to reach him, and carry him back to the border of the lake?
InputThere are several test cases in the input.
The first line contains an integer T (1 <= T <= 20) -- the number of test cases.
For each case:
The first line contains three real numbers Ts, Vr, Vs. 0 <Ts <108, 0 <Vs <Vr <108.
The second line contains two real numbers Xo, Yo, indicate the position (Xo, Yo) of you at current.
The third line contains two real numbers Xp, Yp, indicate the position (Xp, Yp) of the person you are going to save.
The forth line contains only one integer N -- the number of vertices of the lake. 3 <= N <= 50000.
The follow N lines, each line contains two real numbers x, y, indicating one of the vertex (x, y) of the lake. the vertices of lake are listed in either clockwise or counter-clockwise order.
Each coordinate in the input does not exceed 106 by its absolute value. Your position is on the land and the person's is in the lake.
OutputFor each test case, output the minimum time (in seconds) to save the poor person, rounded to two digits after the decimal point. if you cannot save he, output "-1" instead.
Sample Input
2100 2 10 100 03-1 11 10 -11 2 10 100 03-1 11 10 -1
Sample Output
6.39-1
A person falls into the water. You need to save him and tell you the coordinates of the person who falls into the water, the speed on the shore, and the speed in the water, (the speed of saving a person to the shore is half the speed of the water) and tells you the longest time you spent in the water, and this person can enter the water at most once. Ask the minimum time for saving this person. Idea: it is easy to think that the minimum time to return to the shore can be determined when you save people. That is, the shortest distance from this point to n line segments divided by the speed. The time is recorded as Tm. First, find the tangent of the current vertex and the convex packet. In the point between the two tangent, people can directly go over and directly answer the three points (first obtain the two endpoints and obtain the intersection of the straight line and the circle, the inlet point is (x, y) sqr (x-Xp) + sqr (y-Yp) = sqr (Ts-Tm) * )), note that to convert a line segment into a classification discussion is required. In addition, you need to first reach the cut point and then walk along the edge to the corresponding edge. Therefore, first calculate the prefix of the distance and (to calculate two, from two directions), and then give three answers. Then... C ++ AC .... G ++ TLE... No !!
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const double eps=1e-4;const double INF = 1e16;const int maxn = 50000+10;double sumL[maxn],sumR[maxn];double Ts,Vr,Vs;int dcmp(double x) { if(fabs(x) < eps) return 0; else if(x < 0) return -1; else return 1;}struct Point{ double x,y; Point(double x0=0,double y0=0){ x=x0,y=y0; } friend bool operator < (Point a,Point b){ if(a.y!=b.y) return a.y<b.y; else return a.x<b.x; }};Point Poly[maxn],cur,targ;int n;typedef Point Vector;double MinToLandT,ans;inline Vector operator + (Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y); }Vector operator - (Vector A,Vector 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 dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0 ; }inline double sqr(double x) { return x*x;}double Dot(Vector A,Vector B){ return A.x*B.x+A.y*B.y; }double Length(Vector A){ return sqrt(Dot(A,A)); }double Angle(Vector A,Vector B){ return acos(Dot(A,B)/Length(A)/Length(B)); }double Cross(Vector A,Vector B){ return A.x*B.y-A.y*B.x; }Vector Rotate(Vector A,double rad){ return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); }double torad(double ang){ return ang/180.0*acos(-1.0); }void circle_cross_line(Point a,Point b,Point o,double r,Point ret[],int &num) { double x0 = o.x ,y0 = o.y; double x1 = a.x, y1 = a.y; double x2 = b.x, y2 = b.y; double dx = x2-x1, dy = y2-y1; double A = dx*dx+dy*dy; double B = 2*dx*(x1-x0) + 2*dy*(y1-y0); double C = sqr(x1-x0) + sqr(y1-y0)-sqr(r); double delta = B*B-4*A*C; num = 0; if( dcmp(delta) >= 0) { double t1 = (-B - sqrt(delta)) / (2*A); double t2 = (-B + sqrt(delta)) / (2*A); ret[num++] = Point(x1+t1*dx,y1+t1*dy); ret[num++] = Point(x1+t2*dx,y1+t2*dy); }}double DistanceToSegment(Point P,Point A,Point B){ if(A==B) return Length(P-A); Vector v1=B-A,v2=P-A,v3=P-B; if(dcmp(Dot(v1,v2))<0) return Length(v2); else if(dcmp(Dot(v1,v3))>0) return Length(v3); else return fabs(Cross(v1,v2))/Length(v1);}double targetT(Point t,Point st) { if(dcmp(Length(t-targ)/Vs-Ts+MinToLandT) > 0) return INF; else return Length(t-st)/Vr+Length(t-targ)/Vs;}bool cmp(Vector a,Vector b) { if(dcmp(Cross(b , a)) > 0) return true; else if(dcmp(Cross(b,a))== 0) return abs(a.x) < abs(b.x); return false;}void input() { scanf("%lf%lf%lf",&Ts,&Vr,&Vs); scanf("%lf%lf",&cur.x,&cur.y); scanf("%lf%lf",&targ.x,&targ.y); scanf("%d",&n); for(int i = 0; i < n; i++) { scanf("%lf%lf",&Poly[i].x,&Poly[i].y); } Vector t1 = Poly[0]-Poly[1]; Vector t2 = Poly[2]-Poly[1]; if(dcmp(Cross(t1,t2)) > 0) { reverse(Poly,Poly+n); } MinToLandT = INF; for(int i = 0; i < n; i++) { MinToLandT = min(MinToLandT,DistanceToSegment(targ,Poly[i],Poly[(i+1)%n])*2/Vs); }}double thi_Search(Point p0 , Point p1, Point st){ Point l = p0 , r = p1; while(Length(l-r) > eps){ Point lmid = (l*2+r)/3 , rmid = (l+r*2)/3; if(targetT(lmid , st ) < targetT(rmid , st )) r = rmid; else l = lmid; } return targetT((l+r)/2 , st);}void init(int Lid,int Rid) { sumR[Rid] = Length(cur-Poly[Rid]); for(int i = (Rid+1)%n; i != Lid; i = (i+1)%n) { int before = (i-1+n)%n; sumR[i] = sumR[before] + Length(Poly[before]-Poly[i]); } sumL[Lid] = Length(cur-Poly[Lid]); for(int i = (Lid-1+n)%n; i != Rid; i = (i-1+n)%n) { int before = (i+1)%n; sumL[i] = sumL[before] + Length(Poly[before]-Poly[i]); }}bool PointOnSegment(Point o,Point a,Point b) {//o on segment (a,b) if(a.x > b.x) swap(a,b); return (dcmp(b.x-o.x) >= 0 && dcmp(o.x-a.x) >= 0);}void solve() { if(Ts < MinToLandT ) { puts("-1"); return; } Vector vec[maxn]; for(int i = 0; i < n; i++) { vec[i] = Poly[i]-cur; } sort(vec,vec+n,cmp); ans = INF; int Lid = 0,Rid = 0; Point L = vec[0]+cur,R; if(dcmp(Angle(vec[n-1],vec[n-2]))==0) R = vec[n-2]+cur; else R = vec[n-1]+cur; for(int i = 0; i < n; i++) { if(R==Poly[i]) Rid = i; if(L==Poly[i]) Lid = i; } init(Lid,Rid); for(int i = Lid; i != Rid; i = (i+1)%n) { Point o = targ; Point ret[2]; int num; double r = (Ts-MinToLandT)*Vs; Point a = Poly[i],b = Poly[(i+1)%n]; if(a.x > b.x) swap(a,b); circle_cross_line(a,b,o,r,ret,num); if(num==0) continue; if(num==1) { Point t = ret[0]; if(PointOnSegment(t,a,b)) { ans = min(ans,Length(t-cur)); } }else{ Point ep1,ep2; if(PointOnSegment(a,ret[0],ret[1])) { ep1 = a; }else{ ep1 = ret[0]; } if(PointOnSegment(b,ret[0],ret[1])) { ep2 = b; }else{ ep2 = ret[1]; } ans = min(ans,thi_Search(ep1 , ep2 , cur)); } } for(int i = Rid; i != Lid; i = (i+1)%n) { Point o = targ; Point ret[2]; int num; double r = (Ts-MinToLandT)*Vs; Point a = Poly[i],b = Poly[(i+1)%n]; if(a.x > b.x) swap(a,b); circle_cross_line(a,b,o,r,ret,num); double tmp1,tmp2; if(num==0) continue; if(num==1) { Point t = ret[0]; if(PointOnSegment(t,a,b)) { tmp1 = sumL[(i+1)%n] + Length(t-b); tmp2 = sumR[i]+Length(t-a); } }else{ Point ep1,ep2; if(PointOnSegment(a,ret[0],ret[1])) { ep1 = a; }else{ ep1 = ret[0]; } if(PointOnSegment(b,ret[0],ret[1])) { ep2 = b; }else{ ep2 = ret[1]; } tmp1 = sumL[(i+1)%n]/Vr+thi_Search(ep1 , ep2 , Poly[(i+1)%n]); tmp2 = sumR[i]/Vr+thi_Search(ep1 , ep2 , Poly[i]); } ans = min(tmp1,ans); ans = min(tmp2,ans); } ans += MinToLandT; if(ans >= INF) { puts("-1"); }else{ printf("%.2lf\n",ans); }}int main() { int ncase; cin >> ncase; while(ncase--) { input(); solve(); } return 0;}