[SCOI2010] 传送带

三分套三分,数学

传送门:$>here<$


题意:平面上有两条线段$AB$和$CD$,人在$AB$上通行速度为$P$,在$CD$上为$Q$,在平面内则为$R$。问从$A$到$D$的最短时间。

数据范围:均小于1000


$Solution$

我们发现我们的路径一定是沿着$AB$走一段,然后横跨平面,再在$CD$上走一段的。而问题就在于在这两条线段上究竟走多少。

假设我们在$AB$上一直走到$E$,在$CD$上从$F$开始走。那么答案是一个关于$E,F$的二元函数。我们要求这个二元函数的最小值。通过观察我们发现(如何证明???)这两个元的取值都是凸性的,因此三分套三分求最小值即可。

我选择二分距离。设$AE$为$k$。现在要求$E$的坐标,用相似可得$X_E=X_A+\dfrac{AE}{AB}(X_B-X_A)$。其他的同理

反思

关于此类距离问题跟二分三分好像都有密切关系。

$my \ code$

坑点在于如果$A$与$B$重合(或是$C$与$D$重合)时,会$nan$。因此特判。

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 10010;
const int MAXM = 20010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Coordinate{
    double x,y;
};
Coordinate A,B,C,D;
double Q,P,R,l,r,mid,mmid,AB,CD;
inline double sqr(double X){
    return X*X;
}
inline double ABS(double X){
    if(X<0) return -X;
    return X;
}
inline double get_dis(Coordinate A, Coordinate B){
    return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));
}
inline double Calculate(double k, double w){
    double res = k/P + w/Q;
    Coordinate E,F;
    if(AB > 0){
        E.x = A.x + k/AB * (B.x-A.x), E.y = A.y + k/AB * (B.y-A.y);
    }
    else{
        E = A;
    }
    /*防nan*/
    if(CD > 0){
        F.x = D.x - w/CD * (D.x-C.x), F.y = D.y - w/CD * (D.y-C.y);
    }
    else{
        F = C;
    }
    res += get_dis(E,F) / R;
    return res;
}
inline double calc(double k){
    double l = 0, r = CD, mid, mmid;
    while(r - l >= 1e-6){
        mid = (l+r) / 2.0;
        mmid = (mid+r) / 2.0;
        if(Calculate(k,mid) < Calculate(k,mmid)){
            r = mmid;
        }else{
            l = mid;
        }
    }
    return Calculate(k,l);
}
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",&P,&Q,&R);
    AB = get_dis(A,B);
    CD = get_dis(C,D);
    l = 0, r = AB;
    do{
        mid = (l+r) / 2.0;
        mmid = (mid+r) / 2.0;
        if(calc(mid) < calc(mmid)){
            r = mmid;
        }else{
            l = mid;
        }
    }while(r - l >= 1e-6);
    printf("%.2f", calc(l));
    return 0;
}

 

posted @ 2018-11-06 21:39  DennyQi  阅读(343)  评论(0编辑  收藏  举报