AT_abc426_e题解
传送门
题面
高桥和青木在一个二维直角坐标系上沿直线从\((S_x,S_y)\)到\((T_x,T_y)\)走动,速度都为1,当一个人到达了他的终点,那么他会停在那里,直到两人都走完。
那么什么时候两人直线距离最短。请求出这个最短的距离。
思路
分开成两段,一段是路线短的那个人走完且两人走的距离相同(没走完也停下);另一段是路线短的那个人停在终点,等路线长的人走完。
可以用三分求出什么时候直线距离最短。
具体详细步骤
首先我们需要一些结构体,point(存储一个点的横纵坐标)和line(存储两个点,两点一线)
struct point
{
double x, y; // 横纵坐标
};
struct line
{
point s, e; // 起始点和终点
};
接着我们要这几个函数:
1、distance(后简称dis)函数,求出两个点之间的距离,直接利用勾股定理即可
double dis(point& p1, point& p2)
{
double t1 = p1.x - p2.x; // 纵向距离
double t2 = p1.y - p2.y; // 横向距离
return sqrt(t1 * t1 + t2 * t2); // 勾股定理求最短距离
}
2、position after moving(后简称pam)函数,求出从一个人沿着他的路线走\(t\)秒后到达的位置。可以用比例来做。
point pam(line& L, double t)
{
double X = L.e.x - L.s.x; // 纵向距离
double Y = L.e.y - L.s.y; // 横向距离
double len = dis(L.s, L.e); // 直线距离
double r = t / len; // t占的比例
r = min(r, 1.0); // 到达终点就停下,所以不会超过终点。
return { L.s.x + r * X, L.s.y + r * Y }; // 按照比例分别求出位置的行与列。
}
3、distance after moving(后简称dam)函数,求出两个人分别沿着他们的路径走\(t\)秒后的直线距离,可以借用dis和pam函数。找到两人的位置然后求距离。
double dam(line& L1, line& L2, double t)
{
point p1 = pam(L1, t); // 一个人到达的位置
point p2 = pam(L2, t); // 另一人到达的位置
return dis(p1, p2); // 直线距离
}
4、closest moment(后简称cm) 函数,用三分法求出它们的距离何时最短。
求法:
由于我们已经将问题分成两段。可以看出每一段他们的距离随着时间变化一定是个谷型(即dam的函数图像),三分法是如何求出谷底的呢?
最开始\(L=0,R=路线长度\)
每次我们在谷上在\(L\)到\(R\)中随意找到两个位置,记为\(mid1,mid2 (mid1 < mid2)\),当\(dam(L1,L2,mid1) < dam(L1,L2,mid2)\)时,可以发现答案只可能在\(mid1\)到\(R\)中间。而当\(dam(L1,L2,mid1) > dam(L1,L2,mid2)\)时,可以发现答案只可能在\(L\)到\(mid2\)中间。(可以自己画一下)
我们可以每次让\(mid1 = (L+L+R)/3,mid2 = (L+R+R)/3\)
double cm(line& L1, line& L2)
{
double len = max(dis(L1.s, L1.e), dis(L2.s, L2.e)); // 路径长度(注意由于第二段两个长度是不同的,取max)
double L = 0, R = len;
for (int i = 1; i <= 50; i++) // 多做几次不易错
{
double mid1 = (L + L + R) / 3; // 找到mid1
double mid2 = (L + R + R) / 3; // 找到mid2
if (dam(L1, L2, mid1) < dam(L1, L2, mid2)) // 谷底在左边
R = mid2;
else // 谷底在右边
L = mid1;
}
return L;
}
5、最后一个,解题solve函数,详情看注释
void solve()
{
line L1, L2;
cin >> L1.s.x >> L1.s.y >> L1.e.x >> L1.e.y; // 输入第一个人的路线
cin >> L2.s.x >> L2.s.y >> L2.e.x >> L2.e.y; // 输入第二个人的路线
double mnlen = min(dis(L1.s, L1.e), dis(L2.s, L2.e)); // 找到较短的路线长度
line k1, k2, k3, k4; // 分成两次,每次两人,一共四段
// 分成两段,第一段时双方都走mnlen的时间,其中一人走完,一人没有走完。然后第二段一人不动,一人走完剩下的。
k1.s = L1.s; k1.e = pam(L1, mnlen); // 第一段第一个人。
k2.s = L2.s; k2.e = pam(L2, mnlen); // 第一段第二个人。
k3.s = k1.e; k3.e = L1.e; // 第二段第一个人
k4.s = k2.e; k4.e = L2.e; // 第二段第二个人
double ans1 = dam(k1, k2, cm(k1, k2)); // 找到第一段的最近距离
double ans2 = dam(k3, k4, cm(k3, k4)); // 找到第二段的最近距离
printf("%.8f\n", min(ans1, ans2)); // 比一下,看哪个最近。
}
6、main主函数:可以加个快读(1946ms -> 865ms)输入\(T\),运行\(T\)次solve函数,然后return 0;
int main()
{
ios::sync_with_stdio(false); // 快读
cin.tie(0); // 快读
int T; // 数据组数
cin >> T;
while (T--)
{
solve();
}
return 0;
}
代码
高清代码附上:
#include <bits/stdc++.h>
using namespace std;
const int N = 50;
struct point
{
double x, y;
};
struct line
{
point s, e;
};
double dis(point& p1, point& p2)
{
double t1 = p1.x - p2.x;
double t2 = p1.y - p2.y;
return sqrt(t1 * t1 + t2 * t2);
}
point pam(line& L, double t)
{
double X = L.e.x - L.s.x;
double Y = L.e.y - L.s.y;
double len = dis(L.s, L.e);
double r = t / len;
r = min(r, 1.0);
return { L.s.x + r * X, L.s.y + r * Y };
}
double dam(line& L1, line& L2, double t)
{
point p1 = pam(L1, t);
point p2 = pam(L2, t);
return dis(p1, p2);
}
double cm(line& L1, line& L2)
{
double len = max(dis(L1.s, L1.e), dis(L2.s, L2.e));
double L = 0, R = len;
for (int i = 1; i <= N; i++)
{
double mid1 = (L + L + R) / 3;
double mid2 = (L + R + R) / 3;
if (dam(L1, L2, mid1) < dam(L1, L2, mid2))
R = mid2;
else
L = mid1;
}
return L;
}
void solve()
{
line L1, L2;
cin >> L1.s.x >> L1.s.y >> L1.e.x >> L1.e.y;
cin >> L2.s.x >> L2.s.y >> L2.e.x >> L2.e.y;
double mnlen = min(dis(L1.s, L1.e), dis(L2.s, L2.e));
line k1, k2, k3, k4;
k1.s = L1.s; k1.e = pam(L1, mnlen);
k2.s = L2.s; k2.e = pam(L2, mnlen);
k3.s = k1.e; k3.e = L1.e;
k4.s = k2.e; k4.e = L2.e;
double ans1 = dam(k1, k2, cm(k1, k2));
double ans2 = dam(k3, k4, cm(k3, k4));
printf("%.8f\n", min(ans1, ans2));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
完结撒花~~~~~~~

浙公网安备 33010602011771号