题意:给定两条狗的行走路线,一直两条狗同时出发同时到达,问路途中的最远和最近距离。
思路:先简化版本,如果甲乙都仅沿着两条线段向前跑,那么他们之间的最短和最长距离怎么算? 假设甲的速度向量为v1(速度向量指甲单位时间所走的位移向量),乙的速度向量为v2. 因为运动是相对的,可以把甲看成是静止的,乙运动,因此问题转化成求最小的点到线段的最小或最大距离。(可以把甲看成是静止不动的,而让乙一个人以v2-v1的速度向量去运动)
画图证明一下:乙一个人以v2-v1的速度运动时,包含的距离组成的集合一定包含了甲乙同时运动时的距离集。
那么,我们对于每段分析,看谁先到达该线段的终点,则该段可以用上面的方法求。
把a看成不动的,则有b运动到了cb+vb-va(其中va,vb分别为a和b的位移向量,ca,cb分别为a和b初始位置)
那么就转换为sa到线段cb+vb-va的距离。(最小距离为点到直线,而最大距离一定在线段两边)
解完之后,还要更新甲乙的位置,如果正好到达下一个拐点,还要更新Sa和Sb。
复杂度(A+B)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<memory.h> 7 #include<cstdlib> 8 #include<vector> 9 #define clc(a,b) memset(a,b,sizeof(a)) 10 #define LL long long int 11 using namespace std; 12 const int inf=0x3f3f3f3f; 13 const double eps = 1e-10; 14 const int N = 300 + 5; 15 const double pi= acos(-1.0); 16 17 struct Point 18 { 19 double x,y; 20 Point(double x=0,double y=0):x(x),y(y) {} 21 }; 22 23 typedef Point Vector; 24 25 Vector operator +(Vector A,Vector B) //向量+向量=向量,向量+点=点 26 { 27 return Vector(A.x+B.x,A.y+B.y); 28 } 29 30 Vector operator -(Point A,Point B) //点-点=向量 31 { 32 return Vector(A.x-B.x,A.y-B.y); 33 } 34 35 Vector operator *(Vector A,double p) //向量*数=向量 36 { 37 return Vector(A.x*p,A.y*p); 38 } 39 40 Vector operator /(Vector A,double p) //向量/数=向量 41 { 42 return Vector(A.x/p,A.y/p); 43 } 44 45 bool operator <(const Point &a,const Point &b) 46 { 47 return a.x<b.x||(a.x==b.x&&a.y<b.y); 48 } 49 50 int dcmp(double x) 51 { 52 if(fabs(x)<eps) return 0; 53 else 54 return x<0?-1:1; 55 } 56 57 bool operator ==(const Point &a,const Point &b) 58 { 59 return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; 60 } 61 62 double Dot(Vector A,Vector B) //求点积 63 { 64 return A.x*B.x+A.y*B.y; 65 } 66 67 double Length(Vector A) //利用点积求向量长度 68 { 69 return sqrt(Dot(A,A)); 70 } 71 72 double Angle(Vector A,Vector B) //利用点积求夹角 73 { 74 return acos(Dot(A,B)/Length(A)/Length(B)); 75 } 76 77 double Cross(Vector A,Vector B) // 叉积 78 { 79 return A.x*B.y-A.y*B.x; 80 } 81 82 double Area(Point A,Point B,Point C) 83 { 84 return Cross(B-A,C-A); 85 } 86 Vector Rotate(Vector A,double rad) //向量的逆时针旋转 87 { 88 return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); 89 90 } 91 92 //调用前确保两条直线相交。当且仅当Cross(v,w)非零。 93 Point GetLineIntersection(Point P,Vector v, Point Q,Vector w) //计算两条直线P+tv和Q+tw的交点 94 { 95 Vector u=P-Q; 96 double t=Cross(w,u)/Cross(v,w); 97 return P+v*t; 98 } 99 100 //线段规范相交的充要条件是:每条线段的两个端点都在另一条线段的两侧(两侧指叉积的符号不同) 101 bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2) //线段相交判定 102 { 103 double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1), 104 c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1); 105 return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0; 106 } 107 // 判断一个点是否在一条线段(不包含端点) 108 bool OnSegment(Point p, Point a1, Point a2) 109 { 110 return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0; 111 } 112 113 double DistanceToLine(Point P,Point A,Point B) //判断点到直线的距离(两点式) 114 { 115 Vector v1=B-A,v2=P-A; 116 return fabs(Cross(v1,v2))/Length(v1); 117 } 118 119 double DistanceToSegment(Point P,Point A,Point B) //判断点到线段的距离 120 { 121 if(A==B) return Length(P-A); 122 Vector v1=B-A,v2=P-A,v3=P-B; 123 if(dcmp(Dot(v1,v2))<0) 124 return Length(v2); 125 else if(dcmp(Dot(v1,v3))>0) 126 return Length(v3); 127 else 128 return fabs(Cross(v1,v2))/Length(v1); 129 } 130 131 double Min,Max; 132 Point P[60],Q[60]; 133 134 void Update(Point P,Point A,Point B) //更新最小最大距离 135 { 136 Min=min(Min,DistanceToSegment(P,A,B)); 137 Max=max(Max,Length(P-A)); 138 Max=max(Max,Length(P-B)); 139 } 140 141 int main() 142 { 143 int T,A,B,i,j; 144 int icase=1; 145 scanf("%d",&T); 146 while(T--) 147 { 148 scanf("%d %d",&A,&B); 149 for(i=0; i<A; i++) 150 scanf("%lf %lf",&P[i].x,&P[i].y); 151 for(i=0; i<B; i++) 152 scanf("%lf %lf",&Q[i].x,&Q[i].y); 153 double LenA=0,LenB=0; 154 for(i=0; i<A-1; i++) 155 LenA+=Length(P[i+1]-P[i]); 156 for(i=0; i<B-1; i++) 157 LenB+=Length(Q[i+1]-Q[i]); 158 int Sa=0,Sb=0;//为刚经过的拐点的编号; 159 Point Pa=P[0],Pb=Q[0]; 160 Min=inf,Max=-inf; 161 while(Sa<A-1&&Sb<B-1) 162 { 163 double La=Length(P[Sa+1]-Pa);//甲到下一个拐点的距离 164 double Lb=Length(Q[Sb+1]-Pb);//乙到下一个拐点的距离 165 double T=min(La/LenA,Lb/LenB);//取合适的单位,让甲乙的速度分别为LenA,LenB 166 Vector va=(P[Sa+1]-Pa)/La*T*LenA; 167 Vector vb=(Q[Sb+1]-Pb)/Lb*T*LenB; 168 Update(Pa,Pb,Pb+vb-va); 169 Pa=Pa+va; 170 Pb=Pb+vb; 171 if(Pa==P[Sa+1]) Sa++; 172 if(Pb==Q[Sb+1]) Sb++; 173 } 174 printf("Case %d: %.0lf ",icase++, Max-Min); 175 } 176 return 0; 177 }