题意 :给出四个点,前两个点确定一条直线,后面两个点确定另外一条直线。有两个人,分别从两条直线的起点以同样的速度出发,当一个人到达终点时,另外一个人继续前进,问两个人移动过程中的最短距离。
题解 :这两个人前进过程中的距离函数是一个有极值的凹函数,所以只需要三分一下时间,求出该时间下两点的坐标,然后在求出距离。需要注意一个人到达终点后,另外一个人继续前进,所以需要分成两段,第一段为0 - min(d1,d2),第二段为min(d1,d2) - max(d1,d2) 。还有个难点就是求出该时间下各个点的坐标。需要预先用反正切求出直线与x轴的夹角,然后配合正弦函数和余弦函数求出点的坐标,最后在计算两点距离。注意这题卡精度,要限定三分的次数。
#include<bits/stdc++.h> using namespace std; const double pi = acos(-1); #define inf 0x3f3f3f3f #define ll long long const int maxn = 20010; const int mod = 1e9 + 7; double X1,X2,X3,X4,Y1,Y2,Y3,Y4,angle1,angle2,d1,d2,midl,midr; double getDist(double ax, double ay, double bx, double by){ return sqrt((ax - bx)*(ax - bx) + (ay - by)*(ay - by)); } double f(double t){ double t1 = min(d1, t); double t2 = min(d2, t); double xt1 = t1*cos(angle1); double yt1 = t1*sin(angle1); double xt2 = t2*cos(angle2); double yt2 = t2*sin(angle2); double _x1 = X1 + xt1; double _y1 = Y1 + yt1; double _x2 = X3 + xt2; double _y2 = Y3 + yt2; return getDist(_x1, _y1, _x2, _y2); } double sf(double l, double r){ for(int i = 1;i <= 10000; i++){ midl = l + (r - l)/3; midr = r - (r - l)/3; if(f(midl) > f(midr)) l = midl; else r = midr; } return f(midr); } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>X1>>Y1>>X2>>Y2; cin>>X3>>Y3>>X4>>Y4; angle1 = atan2(Y2 - Y1, X2 - X1); angle2 = atan2(Y4 - Y3, X4 - X3); d1 = getDist(X1,Y1,X2,Y2); d2 = getDist(X3,Y3,X4,Y4); double mn = min(d1,d2); double mx = max(d1,d2); double result = min(sf(0, mn), sf(mn, mx)); cout<<fixed<<setprecision(12)<<result<<endl; return 0; }该场比赛部分题目可以参考该bolg:Training 4【2020 ICPC Universidad Nacional de Colombia Programming Contest】