之前没学过三分,不过猜想过它的那个原理,跟二分的差不多,都是逼近的思想 这次月赛的D题,是三分的,比赛时,搞不出,回来才发现枚举AB的时间可能会逼近不到端点的情况,加了这个判断就过了。。。 回来再试了下两重三分的。。。贴贴代码。。。
/**//* 题意:有两条线段,AB,CD 在AB上走速度为P,CD上走为Q,其余地方为R 问从A到D的最短时间
三分,可以处理凸函数峰值,及单调函数 m1,m2取法只要在left,right之内就行吧,这里用黄金比例 记住: 如果m1更接近峰值,则去掉m2右边 如果m2更接近峰值,则去掉m1左边 */ #include<cstdio> #include<cstring> #include<cmath>
const double eps=1e-5;
struct Point { double x,y; }A,B,C,D,AA,DD;
double P,Q,R;
double dist(Point &a,Point &b) { return sqrt(eps+(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); //要加eps 比较那些加不加应该没关系 } double f(double tc) { DD.x=D.x+(C.x-D.x)/dist(C,D)*tc*Q; DD.y=D.y+(C.y-D.y)/dist(C,D)*tc*Q; return tc+dist(AA,DD)/R; } int main() { //freopen("in","r",stdin); int T; scanf("%d",&T); while(T--){ scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y); scanf("%lf%lf%lf%lf",&C.x,&C.y,&D.x,&D.y); scanf("%lf%lf%lf",&P,&Q,&R); double ans=1000000000.0; bool flag=true; for(double ta=0;flag;ta+=0.01)//枚举在AB走了多长时间 { if(ta>eps+dist(A,B)/P){//ta>dist(A,B)/P,这样会漏掉了端点,但有可能取到端点,所以要特判! ta=dist(A,B)/P; flag=false; } AA.x=A.x+(B.x-A.x)/dist(A,B)*ta*P; AA.y=A.y+(B.y-A.y)/dist(A,B)*ta*P; double left=0,right=dist(C,D)/Q; while(right-left>eps) { double m1=right-(right-left)*0.618; double m2=left+(right-left)*0.618; if(f(m1)>f(m2)+eps)left=m1; else right=m2; } if(f(left)+ta+eps<ans)ans=f(left)+ta; } printf("%.2f\n",ans); } return 0; }
上面那个是枚举在AB走的时间,比较慢,这个两重三分的,0ms
/**//* 由于有两个自变量ta,tc分别表示在AB,CD上走的时间,需要降维 上面那种是枚举降维,这里对ta也三分来降维,快了好多 */ #include<cstdio> #include<cstring> #include<cmath>
const double eps=1e-5;
struct Point { double x,y; }A,B,C,D,AA,DD;
double P,Q,R;
double dist(Point &a,Point &b) { return sqrt(eps+(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); //要加eps 比较那些加不加应该没关系 } double f(double tc) { DD.x=D.x+(C.x-D.x)/dist(C,D)*tc*Q; DD.y=D.y+(C.y-D.y)/dist(C,D)*tc*Q; return tc+dist(AA,DD)/R; } double cal(double ta) { AA.x=A.x+(B.x-A.x)/dist(A,B)*ta*P; AA.y=A.y+(B.y-A.y)/dist(A,B)*ta*P; double left=0,right=dist(C,D)/Q; while(right-left>eps) { double m1=right-(right-left)*0.618; double m2=left+(right-left)*0.618; if(f(m1)>f(m2)+eps)left=m1; else right=m2; } return f(left)+ta; } int main() { //freopen("in","r",stdin); int T; scanf("%d",&T); while(T--){ scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y); scanf("%lf%lf%lf%lf",&C.x,&C.y,&D.x,&D.y); scanf("%lf%lf%lf",&P,&Q,&R); double low=0,high=dist(A,B)/P;//注意high是这个,不是无穷,因为限定了在AB内 while(high-low>eps) { double m=high-(high-low)*0.618; double mm=low+(high-low)*0.618; if(cal(m)>cal(mm)+eps)low=m; else high=mm; } printf("%.2f\n",cal(low)); } return 0; }
|