【bzoj1857】[Scoi2010]传送带

两条传送带AB和CD,在上面移动速度分别为 v1 v2 ,其他地方移动速度为 v0 ,求A到D的最短时间。
隽爷说是三分
于是yy了一节数学课的证明。。。
后来发现尼玛这不是随便证么。。。。

先把两条传送简化成一条线段AB和一个点D,线段上速度为 v1 ,其他为 v0
显然有一个点P使得P在AB上且 t=APv1+PDv0 为最小值
那么原命题就转化成证明 AP t 的函数关系是一个单峰函数。
A(x1,y1) , D(x2,y2) , P(x0,y0)
题目中所有的点都是在第一象限,再出于简化考虑,把整个图旋转一下,使得AB平行于X轴,这样就有y0恒不变,t与 AP 的关系变成t与 x0 的关系。
可以有 t=x0x1v1+(x2x0)2+(y2y0)2v2
为了方便,先设 dis=(x2x0)2+(y2y0)2 ,显然 dis0
然后把t求个导
t=1v1+(dis)disv2dis
其中 dis=[x202x2x0+x22+(y0y2)2]
          =2x02x2
那么 t=1v1+2(x0x2)disv2dis
这玩意最多只有一个零点
所以最开始那玩意就是单峰的了
然后别的情况就从这个最基本的情况扩展出去就好
于是乎在AB,CD上的离开、进入点可以三分搞搞
(以上口胡)
似乎WJMZBMR写的是退火orz
属于乱搞。。。?
跪跪跪跪…………
我的代码跑的好慢啊TAT

#include <bits/stdc++.h>

typedef double db;

const db eps = 1e-7;

db fsqr(db x) { return x * x ; }

struct point { 
    db x , y;

    point(db x = 0 , db y = 0):x(x) , y(y) { }

    friend point operator+(point a , point b)
        { return point(a.x + b.x , a.y + b.y) ; }

    friend point operator-(point a , point b)
        { return point(a.x - b.x , a.y - b.y) ; }

    friend point operator*(point a , db b)
        { return point(a.x * b , a.y * b) ; }

    friend point operator/(point a , db b)
        { return point(a.x / b , a.y / b) ; }

    friend db dis(point a , point b)
        { return sqrt(fsqr(a.x - b.x) + fsqr(a.y - b.y)) ; }
}A , B , C , D;

db v1 , v2 , v0;

db find(point D , point A , point B) {
    point l = A , r = B ;
    while (dis(l , r) > eps) {
        point d = (r - l) / 3.0 , m1 = l + d , m2 = r - d;
        db   r1 = dis(m1 , B) / v2 + dis(m1 , D) / v0 ,
             r2 = dis(m2 , B) / v2 + dis(m2 , D) / v0 ;
        if (r1 < r2) r = m2 ; else l = m1;
    }
    return dis(l , B) / v2 + dis(l , D) / v0 ;
}

int main() {
    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" , &v1 , &v2 , &v0);
    point l = A , r = B;
    while (dis(l , r) > eps) {
        point d = (r - l) / 3.0 , m1 = l + d , m2 = r - d;
        db t1 = dis(m1 , A) / v1 , t2 = dis(m2 , A) / v1;
        db r1 = find(m1 , C , D) , r2 = find(m2 , C , D);
        r1 += t1 , r2 += t2 ;
        if (r1 < r2) r = m2 ; else l = m1 ;
    }
    printf("%.2lf\n" , find(l , C , D) + dis(l , A) / v1);
    return 0;
}

你可能感兴趣的:(【bzoj1857】[Scoi2010]传送带)