之前没学过三分,不过猜想过它的那个原理,跟二分的差不多,都是逼近的思想
   这次月赛的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;
}