题意:两只狗,Ranga和Banga,分别在两条不同的路径上奔跑。他们每个人都花费了T秒在不同的速度下,Ranga用一个均匀速度Rm/s奔跑,Banga用一个均匀速度Sm/s奔跑。两只狗在在起点和终点的时间是相同的。让我们定义D(t)为两只狗在t时相距的距离。狗的距离定义为他们在他们的旅程的最大距离和最小距离之差。\(Dog Distance = {max(D(a)) 0 <= a <= T} - {min(D(b)) 0 <= b <= T}\)。给出两只狗的路径,你的目的是去寻找两只狗的距离。每条路径都有N个点组成。
分析:可以认为甲静止不动,乙自己沿着直线走,问题转化为求点到线段的最小距离或最大距离。这道题没有指明速度是多少,我们可以假定速度为整段路程,那么T = min(La / LenA, Lb / LenB),我们把问题拆分成简化版的问题,每次计算他俩谁先到达拐点,那么在这个时间点之间的问题就是我们刚才讨论过的"简化版"。Vector Va = (P[Sa + 1] - Pa) / La * T * LenA。先求出位移的单位向量,即\(位移向量 / 位移长度 * 时间 * 速度\),就可以得到在T时的位移向量,然后我们更新min和max,然后使用update(Pa, Pb, Pb + Vb - Va),这里假定a点静止不动,b点在动,那么Pb + Vb - Va就是b点相对于a移动的距离,然后求解a点到这条线段的距离即可。可以分为3种情况,如下
,两边是最大的距离,中间是最短距离。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 60;
const double eps = 1e-6;
struct Point
{
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
};
typedef Point Vector;
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);
}
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 Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }
double Length(Vector A) { return sqrt(Dot(A, 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;
if (dcmp(Dot(v1, v2)) < 0) return Length(v2);
else if (dcmp(Dot(v1, v3)) > 0) return Length(v3);
else return fabs(Cross(v1, v2)) / Length(v1);
}
//第一条路径的点个数,第二条路径的点个数
int A, B;
//第一条路径的点,第二条路径的点
Point P[N], Q[N];
double Min, Max;
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));
}
Point read_point()
{
double x, y;
scanf("%lf%lf", &x, &y);
return Point(x, y);
}
int main()
{
int t;
scanf("%d", &t);
int c = 0;
while (t--)
{
//第一条路径的点个数,第二条路径的点个数
scanf("%d%d", &A, &B);
for (int i = 0; i < A; ++i) P[i] = read_point();
for (int i = 0; i < B; ++i) Q[i] = read_point();
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]);
//拐点编号
int Sa = 0, Sb = 0;
//现处于的点
Point Pa = P[0], Pb = Q[0];
Min = 1e9, Max = -1e9;
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);
Pa = Pa + Va;
Pb = Pb + Vb;
if (Pa == P[Sa + 1]) ++Sa;
if (Pb == Q[Sb + 1]) ++Sb;
}
printf("Case %d: %.0lf\n", ++c, Max - Min);
}
return 0;
}