OI中有种暴力的解法就是把区间离散化,是可以过部分数据的。
在搞清这题的AC算法之前先要搞清一个问题,如何求单峰函数的极值。

假设我们要求一个
单峰函数
$ f(x) $ 在区间 $ [a,b] $ 上的极值,如图所示。函数图像上两点 $ P(x_p,y_p) , Q(x_q,y_q) $ 保证 $ [x_p,y_p] ⊂ [a,b] $。因为函数是单峰的,如果有 $ y_p > y_q $,则可以断定极值点一定不在 $ P $ 左边。这一点很重要。这意味着我们可以缩小区间范围。缩小范围的方法就是把区间不断三分,比较两个分点,舍去三个区间其中一个子区间。当区间长度小于一个绝对小的数的时候,我们可以认为找到了这个极值点,当然这个绝对小的数也是人为定义的,它可以是1E-4
等等。那么我们再来看这一题。为了达到最少的时间,首先不能出现
来回走
的路径,所以我们的路径一定是这样的:经过AB上一点S,经过CD上一点T,整个路径就是A->S->T->D
,下面我们考虑如何让这条路径最优(时间最短)。
假设S是一个定点,那么我们只要考虑路径
S->T->D
最优,通过画图可以发现这条路径所用的时间关于T点位置的函数是单峰的,也就是说T点的位置如果从C到D一一枚举,耗费的时间会经过一个先递减再递增的过程(这里的单峰有猜测的因素,不过也可以给出严格的证明),那么要找到这条路径的最优解,需要对CD线段进行三分。同理,S作为动点时,路径
A->S->T->D
耗费的时间关于S点位置的函数也是单峰的。所以我需要对AB线段进行三分,确定最优的S点。因此,水到渠成,三分套三分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#include <iostream> #include <cmath> #include <iomanip> #define eps 1e-3 using namespace std; int T; double ax,ay,bx,by,cx,cy,dx,dy,p,q,r,rv1,rv2,rvm; inline double dist(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double timecal(double x,double y) { double lx,ly,rx,ry,dx1,dy1,dx2,dy2,dt1,dt2; lx=cx; ly=cy; rx=dx; ry=dy; while (fabs(lx-rx)>eps || fabs(ly-ry)>eps) { dx1=lx+(rx-lx)/3.0; dy1=ly+(ry-ly)/3.0; dx2=lx+(rx-lx)/3.0*2; dy2=ly+(ry-ly)/3.0*2; dt1=dist(ax,ay,x,y)/p+dist(x,y,dx1,dy1)/r+dist(dx1,dy1,dx,dy)/q; dt2=dist(ax,ay,x,y)/p+dist(x,y,dx2,dy2)/r+dist(dx2,dy2,dx,dy)/q; if (dt1>dt2) { lx=dx1; ly=dy1; } else { rx=dx2; ry=dy2; } } return dist(ax,ay,x,y)/p+dist(x,y,lx,ly)/r+dist(lx,ly,dx,dy)/q; } int main() { double lx,ly,rx,ry,dx1,dy1,dx2,dy2,dt1,dt2,ans; ios::sync_with_stdio(false); cin>>T; for (int it=1;it<=T;++it) { cin>>ax>>ay>>bx>>by; cin>>cx>>cy>>dx>>dy; cin>>p>>q>>r; lx=ax; ly=ay; rx=bx; ry=by; while (fabs(lx-rx)>eps || fabs(ly-ry)>eps) { dx1=lx+(rx-lx)/3.0; dy1=ly+(ry-ly)/3.0; dx2=lx+(rx-lx)/3.0*2; dy2=ly+(ry-ly)/3.0*2; dt1=timecal(dx1,dy1); dt2=timecal(dx2,dy2); if (dt1>dt2) { lx=dx1; ly=dy1; } else { rx=dx2; ry=dy2; } } ans=timecal(lx,ly); cout<<fixed<<setprecision(2)<<ans<<endl; } return 0; } |
图挂了。。。
换cdn域名的时候忘记改了23333
已更新