[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; }