【分析】 先看一种简单的情况:甲和乙的路线都是一条线段。因为运动是相对的,因此也可以认为甲静止不动,乙沿着自己的直线走,因此问题转化为求点到线段的最小距离和最大距离; 有了简化版的分析,只需要模拟整个过程,设现在甲的位置在Pa,刚刚经过编号为Sa的拐点;乙的位置是Pb,刚刚经过编号为Sb的拐点,则我们只需要计算他们俩谁先到拐点,那么在这个时间点之前的问题就是我们刚刚讨论过的“简化版”。求解完毕之后,需要更新甲乙的位置,如果正好到达下一个拐点,还需要更新Sa和/或Sb,然后继续模拟。因为每次至少有一条狗到达拐点,所以子问题的求解次数不会超过A+B。
#include<cstdio> #include<cmath> #include<iostream> #define PI acos(-1.0) #define NN 1e9 const int mmax=60; double Max,Min; using namespace std; struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y){}//构造函数,方便代码编写 }; typedef Point Vector;//Vector只是Point的别名 //向量+向量=向量; 向量+点=点 Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);} //点-点=向量 Vector operator - (Point A,Point B){return Vector(A.x-B.x,A.y-B.y);} //向量*数=向量 Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);} //向量/数=向量 Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);} // bool operator < (const Point& a,const Point& b){return a.x<b.x||(a.x==b.x && a.y<b.y);} // const double eps = 1e-10; //三态函数 int dcmp(double x){if(fabs(x)<eps)return 0;else return x < 0 ? -1 : 1;} //相等 bool operator == (const Point& a,const Point& b){return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;} double Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;} double length(Vector A){return sqrt(Dot(A,A));} double Angle(Vector A,Vector B){return acos(Dot(A,B)/length(A)/length(B));} double Cross(Vector A,Vector B){return A.x*B.y-B.x*A.y;} double Area2(Point A,Point B,Point C){return Cross(B-A,C-A);} double DistanceToSegment(Point P,Point A,Point B) { if(A==B)return length(P-A); Vector v1=B-A,v2=P-A,v3=P-B; //点积判断P点投影的位置 if(dcmp(Dot(v1,v2))<0) return length(v2);//A左边 else if(dcmp(Dot(v1,v3)>0))return length(v3);//B右边 else return fabs(Cross(v1,v2))/length(v1); } //输入函数 Point read_point(Point &P) { scanf("%lf%lf",&P.x,&P.y); return P; } void update(Point P,Point A,Point B) { Min=min(Min,DistanceToSegment(P,A,B)); Max=max(Max,length(P-A)); Max=max(Max,length(P-B)); } int main() { int T,A,B,kase=1; Point P[mmax],Q[mmax]; scanf("%d",&T); while(T--) { scanf("%d%d",&A,&B); for(int i=0;i<A;i++) { P[i]=read_point(P[i]); } for(int i=0;i<B;i++) { Q[i]=read_point(Q[i]); } double LenA=0,LenB=0; for(int i=0;i<A-1;i++) { LenA+=length(P[i+1]-P[i]); } for(int i=0;i<B-1;i++) { LenB+=length(Q[i+1]-Q[i]); } //LenA和LenB表示距离同时也表示速度 int Sa=0,Sb=0; Max=-NN; Min=NN; Point Pa=P[0],Pb=Q[0];//当前位置 while(Sa<A-1&&Sb<B-1) { double La=length(P[Sa+1]-Pa);//甲到下一拐点的距离 double Lb=length(Q[Sb+1]-Pb);//乙到下一拐点的距离 double t=min(La/LenA,Lb/LenB); Vector Va=(P[Sa+1]-Pa)/La*t*LenA;//甲的位移向量 Vector Vb=(Q[Sb+1]-Pb)/Lb*t*LenB;//乙的位移向量 update(Pa,Pb,Pb+Vb-Va);/****把a看成静止的,则b相对从Pb运动到了Vb-Va处。****/ Pa=Pa+Va; Pb=Pb+Vb; if(Pa==P[Sa+1])Sa++; if(Pb==Q[Sb+1])Sb++; } printf("Case %d: %.0lf\n",kase++,Max-Min); } return 0; } /** 2 2 2 0 0 10 0 0 1 10 1 3 2 635 187 241 269 308 254 117 663 760 413 **/
时间: 2024-10-06 08:05:07