将军饮马问题的升级版
二维平面中要从A到D,给出两条线段AB,CD,分别在线段AB,CD,以及空白处的速度为P,Q,R 求最少用时
由于最优位置满足“凸性”,且两条线段可以等价,所以可以采取三分答案迭代的写法
值得注意的一点:求两点距离时开方运算会损失一部分精度,一种玄学的方法是在开方前用一个eps加回来?
1 #include <cmath> 2 #include <cstdio> 3 typedef double db; 4 const db eps=1e-9; 5 struct point{db x,y;point(db x=0,db y=0):x(x),y(y){}}A,B,C,D; 6 db P,Q,R,AB,CD; 7 db dis(point A,point B){return sqrt(eps+(A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));} 8 point getAB(db len){return point(A.x+(B.x-A.x)/AB*len,A.y+(B.y-A.y)/AB*len);} 9 point getCD(db len){return point(C.x+(D.x-C.x)/CD*len,C.y+(D.y-C.y)/CD*len);} 10 db third(db len){ 11 point E=getAB(len),F,G; 12 db l=0,r=CD; 13 while(r-l>eps){ 14 db ll=(2*l+r)/3,rr=(l+2*r)/3; 15 F=getCD(ll),G=getCD(rr); 16 db ans1=dis(E,F)/R+dis(F,D)/Q; 17 db ans2=dis(E,G)/R+dis(G,D)/Q; 18 ans1<ans2?r=rr:l=ll; 19 } 20 return dis(A,E)/P+dis(E,F)/R+dis(F,D)/Q; 21 } 22 db work(){ 23 AB=dis(A,B),CD=dis(C,D); 24 db l=0,r=AB; 25 while(r-l>eps){ 26 db ll=(2*l+r)/3,rr=(l+2*r)/3; 27 third(ll)<third(rr)?r=rr:l=ll; 28 } 29 return third(l); 30 } 31 int main(){ 32 int T; 33 for(scanf("%d",&T);T--;) 34 scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y,&C.x,&C.y,&D.x,&D.y), 35 scanf("%lf%lf%lf",&P,&Q,&R), 36 printf("%.2f ",work()); 37 return 0; 38 }