uva 11796 Dog Distance

题意:给定两条狗的行走路线,一直两条狗同时出发同时到达,问路途中的最远和最近距离。

思路:先简化版本,如果甲乙都仅沿着两条线段向前跑,那么他们之间的最短和最长距离怎么算? 假设甲的速度向量为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)

  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 }
View Code
原文地址:https://www.cnblogs.com/ITUPC/p/4868707.html