题目链接:https://ac.nowcoder.com/acm/contest/9925/D
可以分以下几种情况:
①两个人中选一个走完全程
②互相向对面走,走到边界,算两者时间久的那个
③将两人中间某点作为划分点,两个人分别负责走自己的部分
主要是第三点,如果只考虑分类就只能想到一些个别的情况。
实际上两人中间的位置,任意点都可能作为划分点,所以需要用三分。注意一个人走自己的部分有两种走法,选时间最少的那种。
#include <bits/stdc++.h>
using namespace std;
double n;
struct Node {
double pos, v;
}p[2];
double cal(double x) {
double t1 = min((2.0 * x - p[0].pos) / p[0].v, (p[0].pos + x) / p[0].v);
double t2 = min((n + p[1].pos - 2.0 * x) / p[1].v, (2 * (n - p[1].pos) + p[1].pos - x) / p[1].v);
return max(t1, t2);
}
int main(void) {
// freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while (t--) {
scanf("%lf%lf%lf%lf%lf", &n, &p[0].pos, &p[0].v, &p[1].pos, &p[1].v);
if (p[0].pos > p[1].pos) swap(p[0], p[1]);
double ans = 1e18;
// 只算一个人走
ans = min(ans, (p[0].pos + n) / p[0].v);
ans = min(ans, (n + n - p[0].pos) / p[0].v);
ans = min(ans, (p[1].pos + n) / p[1].v);
ans = min(ans, (n + n - p[1].pos) / p[1].v);
double t1, t2;
// <-0 1->
t1 = p[0].pos / p[0].v;
t2 = (n - p[1].pos) / p[1].v;
if (t1 < t2) {
double pos1 = (t2 - t1) * p[0].v;
if (n > pos1)
ans = min(ans, t2 + (n - pos1) / (p[0].v + p[1].v));
}
else {
double pos2 = n - (t1 - t2) * p[1].v;
if (pos2 > 0)
ans = min(ans, t1 + pos2 / (p[0].v + p[1].v));
}
// 0-> <-1直接走,不回头
ans = min(ans, max((n - p[0].pos) / p[0].v, p[1].pos / p[1].v));
// 三分
double l = p[0].pos, r = p[1].pos;
while (l + 1e-6 < r) {
double mid1 = l + (r - l) / 3;
double mid2 = r - (r - l) / 3;
double t1 = cal(mid1);
double t2 = cal(mid2);
if (t1 > t2) l = mid1;
else r = mid2;
}
ans = min(ans, min(cal(l), cal(r)));
printf("%.99f\n", ans);
}
return 0;
}