文章目录
hud 3400——Line belt 题解
问题描述
题目
给定两条线段AB ,CD 一个人在AB 上跑时速度为P,在CD上跑时速度为Q,在其他地方跑时速度为R。求从AD
输入
- 测试数量T
- A点和B点坐标:Ax,Ay,Bx,By
- C点和D点的坐标:Cx,Cy,Dx,Dy
- P,Q ,R
- 以上输入均为整数
数据范围
0<=Ax,Ay,Bx,By,Cx,Cy,Dx,Dy<=1000,1<=P,Q,R<=10
输出
从A到D的最短时间,四舍五入取两位小数
解题思路
双三分法(三分套三分)
题目大意和表示
- 大意: 从A点出发,先走到线段AB上的一点X,在走到线段CD上一点Y,最后走到D点。求出这一过程所需要的最短时间。
- 表示方式:
——>time=|AX|/P+|XY|/R+|YD|/Q
这一点很好理解
分析
分析题目我们容易知道,要求这一段时间的最小值,一定可以在AB和CD上分别找到一点X和一点Y,使得走完整段路径的时间最短。
显然,X,Y都在移动,这样就使得AX,XY,YD这三条边的长度都在变化,这样显然不易于分析理解。
但是我们经过思考后可以知道,当X每位于一个坐标时,就一定有一条XY/R+YD/Q使得该情况的用时最短。XY/R+YD/Q的函数图像显然如下:
函数是一条抛物线,我们想要得出函数的最小值,就不能再使用二分法了,因为二分法要求数据一定时单调递增或递减的。在这里我们显然可以使用三分法来处理了。
XY/R+YD/Q最小值三分代码
double findCD(double ABx, double ABy) {
int cx = Cx;
int cy = Cy;
int dx = Dx;
int dy = Dy;
double mid1x = cx + (dx - cx) / 3.0;
double mid1y = cy + (dy - cy) / 3.0;
double mid2x = cx + 2 * (dx - cx) / 3.0;
double mid2y = cy + 2 * (dy - cy) / 3.0;
double time1 = 0;
double time2 = 0;
do {
time1 = sqrt((mid1x - dx) * (mid1x - dx) + (mid1y - dy) * (mid1y - dy)) / Q +
sqrt((ABx - mid1x) * (ABx - mid1x) + (ABy - mid1y) * (ABy - mid1y)) / R;
time2= sqrt((mid2x - dx) * (mid2x - dx) + (mid2y - dy) * (mid2y - dy)) / Q +
sqrt((ABx - mid2x) * (ABx - mid2x) + (ABy - mid2y) * (ABy - mid2y)) / R;
if (time1 < time2) {
dx = mid2x;
dy = mid2y;
}
else {
cx = mid1x;
cy = mid1y;
}
} while (abs(time1 - time2) > eps);
return time1;
}
继续思考,每一个X都对应着一段XY~YD的最小时间值,这一X位置的时间总和为time=|AX|/P
+|XY|/R+|YD|/Q显然的每一个x位置的时间总和又构成了一个上图的抛物线函数,我们再使用依次三分法,将时间总和的最小值求出。
时间总和time=|AX|/P+|XY|/R+|YD|/Q最小值三分代码:
double findAB() {
int ax = Ax;
int ay = Ay;
int bx = Bx;
int by = By;
double mid1x = ax + (bx - ax) / 3.0;
double mid1y = ay + (by - ay) / 3.0;
double mid2x = ax + 2 * (bx - ax) / 3.0;
double mid2y = ay + 2*(by - ay) / 3.0;
double time1 = 0;
double time2 = 0;
do {
time1 = sqrt((ax - mid1x) * (ax - mid1x) + (ay - mid1y) * (ay - mid1y)) / P +
findCD(mid1x, mid1y);
time2 = sqrt((ax - mid2x)*(ax - mid2x) + (ay - mid2y) * (ay - mid2y) / P +
findCD(mid2x, mid2y));
if (time1 < time2) {
bx = mid2x;
by = mid2y;
}
else {
ay = mid1y;
ax = mid1x;
}
} while (abs(time1 - time2) > eps);
return time1;
}
完整代码
#include<iostream>
using namespace std;
const double eps = 1e-4;
int Ax, Ay, Bx, By;
int Cx, Cy, Dx, Dy;
int P, Q, R;
int T;
double findCD(double ABx, double ABy) {
int cx = Cx;
int cy = Cy;
int dx = Dx;
int dy = Dy;
double mid1x = cx + (dx - cx) / 3.0;
double mid1y = cy + (dy - cy) / 3.0;
double mid2x = cx + 2 * (dx - cx) / 3.0;
double mid2y = cy + 2 * (dy - cy) / 3.0;
double time1 = 0;
double time2 = 0;
do {
time1 = sqrt((mid1x - dx) * (mid1x - dx) + (mid1y - dy) * (mid1y - dy)) / Q +
sqrt((ABx - mid1x) * (ABx - mid1x) + (ABy - mid1y) * (ABy - mid1y)) / R;
time2= sqrt((mid2x - dx) * (mid2x - dx) + (mid2y - dy) * (mid2y - dy)) / Q +
sqrt((ABx - mid2x) * (ABx - mid2x) + (ABy - mid2y) * (ABy - mid2y)) / R;
if (time1 < time2) {
dx = mid2x;
dy = mid2y;
}
else {
cx = mid1x;
cy = mid1y;
}
} while (abs(time1 - time2) > eps);
return time1;
}
double findAB() {
int ax = Ax;
int ay = Ay;
int bx = Bx;
int by = By;
double mid1x = ax + (bx - ax) / 3.0;
double mid1y = ay + (by - ay) / 3.0;
double mid2x = ax + 2 * (bx - ax) / 3.0;
double mid2y = ay + 2*(by - ay) / 3.0;
double time1 = 0;
double time2 = 0;
do {
time1 = sqrt((ax - mid1x) * (ax - mid1x) + (ay - mid1y) * (ay - mid1y)) / P +
findCD(mid1x, mid1y);
time2 = sqrt((ax - mid2x)*(ax - mid2x) + (ay - mid2y) * (ay - mid2y) / P +
findCD(mid2x, mid2y));
if (time1 < time2) {
bx = mid2x;
by = mid2y;
}
else {
ay = mid1y;
ax = mid1x;
}
} while (abs(time1 - time2) > eps);
return time1;
}
int main() {
cin >> T;
while (T--) {
cin >> Ax >> Ay >> Bx >> By;
cin >> Cx >> Cy >> Dx >> Dy;
cin >> P >> Q >> R;
printf("%.2f", findAB());
}
}