题目链接:D-Walker_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海) (nowcoder.com)sa
题意,给你一个线段,端点是0,n,现在给你两个点的位置以及他们的移动速度,问最小需要花费多长时间能够走完整个线段。
这个题目需要分情况讨论:
我们下面只讨论p1在p2左边的情况, p1在p2右边的情况可类似得到
第一种情况是质点1走完全程
第二种情况是质点2走完全程
第三种情况是质点1从p1跑到l,质点2从p2跑到0
第四种情况是质点p1跑完0~Q这段线段,质点p2跑完Q~L这段线段
前三种情况都比较容易求,我在这就不赘述了,最关键的是第四种情况的求法
对于第四种情况我们可以用三分求,枚举Q点,分别计算质点p1跑完0~Q这段线段的最小时间和质点p2跑完Q~L这段线段的最小时间,最后取一个最大值就好了,我们看看如何求p1跑完0~Q这段线段的最小时间,p1有两条路线可走,一个是从p1->Q->0,另一个是从p1->0->Q,分别求出这两种方式的时间取一个最小值即可,质点p2跑完Q~L这段线段的最小时间同理可求得。最后我们直接三分枚举最优点Q即可。
下面是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
double l,p1,v1,p2,v2;
//计算以速度v从a点到x点再到b点所要花费的时间
double f(double a,double x,double b,double v)
{
double t=(fabs(x-a)+fabs(x-b))/v;
return t;
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%lf%lf%lf%lf%lf",&l,&p1,&v1,&p2,&v2);
double x=(min(p1,l-p1)+l);//计算第一个点跑完整个路线花费的时间
double t=x/v1;
x=(min(p2,l-p2)+l);//计算第二个点跑完整个路线花费的时间
t=min(t,x/v2);
if(p1<=p2)
{
t=min(t,max((l-p1)/v1,p2/v2));//计算两点向相反方向跑完整个路线花费的时间
double ll=p1,rr=p2,lmid,rmid;
while(rr-ll>0.0000000001)//三分求取最优点
{
lmid=ll+(rr-ll)/3;
rmid=rr-(rr-ll)/3;
if(max(min(f(p1,0,lmid,v1),f(p1,lmid,0,v1)),min(f(p2,l,lmid,v2),f(p2,lmid,l,v2)))>max(min(f(p1,0,rmid,v1),f(p1,rmid,0,v1)),min(f(p2,l,rmid,v2),f(p2,rmid,l,v2)))) ll=lmid;
else rr=rmid;
}
t=min(t,max(min(f(p1,0,ll,v1),f(p1,ll,0,v1)),min(f(p2,l,ll,v2),f(p2,ll,l,v2))));
}
else
{
t=min(t,max((l-p2)/v2,p1/v1));//计算两点向相反方向跑完整个路线花费的时间
double ll=p2,rr=p1,lmid,rmid;
while(rr-ll>0.0000000001)//三分求取最优点
{
lmid=ll+(rr-ll)/3;
rmid=rr-(rr-ll)/3;
if(max(min(f(p1,l,lmid,v1),f(p1,lmid,l,v1)),min(f(p2,0,lmid,v2),f(p2,lmid,0,v2)))>max(min(f(p1,l,rmid,v1),f(p1,rmid,l,v1)),min(f(p2,0,rmid,v2),f(p2,rmid,0,v2)))) ll=lmid;
else rr=rmid;
}
t=min(t,max(min(f(p1,l,ll,v1),f(p1,ll,l,v1)),min(f(p2,0,ll,v2),f(p2,ll,0,v2))));
}
printf("%.10f\n",t);
}
return 0;
}