C++-HDU3400-Line belt[三分]

将军饮马问题的升级版

二维平面中要从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\n",work());
37     return 0;
38 } 

 

posted @ 2020-02-24 16:27  墨鳌  阅读(231)  评论(0编辑  收藏  举报