NC20276 [SCOI2010]传送带

题目

题目描述

在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段。两条传送带分别为线段AB和线段CD。lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R。现在lxhgww想从A点走到D点,他想知道最少需要走多长时间

输入描述

输入数据第一行是4个整数,表示A和B的坐标,分别为Ax,Ay,Bx,By
第二行是4个整数,表示C和D的坐标,分别为Cx,Cy,Dx,Dy
第三行是3个整数,分别是P,Q,R

输出描述

输出数据为一行,表示lxhgww从A点走到D点的最短时间,保留到小数点后2位

示例1

输入

0 0 0 100
100 0 100 100
2 2 1

输出

136.60

备注

对于 \(100\%\) 的数据,\(1\le A_x,A_y,B_x,B_y,C_x,C_y,D_x,D_y\le10^3\)

题解

知识点:三分,计算几何。

关于时间计算有两个变量,一个是在 \(AB\) 上的终点 \(E\),一个是 \(CD\) 上的起点 \(F\) ,则总时长为 \(\frac{|AE|}{P} + \frac{|EF|}{R} + \frac{|FD|}{Q}\)

先固定 \(E\) ,计算固定 \(E\) 后最短时间,此时总时间关于 \(F\) 是单谷函数,所以可以三分 \(F\) 确定在 \(E\) 固定的情况下时间最短的 \(F\) ,然后就能得到某个 \(E\) 处的最短时间。而若对于每个 \(E\) 都取最短时间作为总a时间,则总时间关于 \(E\) 的函数也是一个单谷函数,所以可以三分 \(E\) ,求出使得总时间最短的点 \(E\) 。于是一个二重三分就能解决问题,里面的确定 \(F\) 得到每个 \(E\) 的最短时间,外面的确定求出使得总时间最短的点 \(E\)

实际上,总时长关于 \(E\)\(F\) 的多元函数只有一个最小值,而对每个 \(E\) 都取最小值得到的总时长关于 \(E\) 的函数是一定过最小点的曲线,因此对 \(E\) 三分就能得到最小值。

细节上用参数方程来实现在直线上三分,用两点距离作为误差判断条件。

坑点:速度和右端点变量名重了,会炸qwq。

时间复杂度 \(O(1)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>

using namespace std;

const double esp = 1e-3;

struct Point {
    double x, y;
}A, B, C, D;
double P, Q, R;//!R 和 r不要搞混了,被坑死了

double dist(Point a, Point b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

Point Fx1(double t) {
    return { (B.x - A.x) * t + A.x,(B.y - A.y) * t + A.y };
}

Point Fx2(double t) {
    return { (D.x - C.x) * t + C.x,(D.y - C.y) * t + C.y };
}

double calc(Point E) {
    double ans = dist(A, E) / P;
    double l = 0, r = 1;
    while (dist(Fx2(l), Fx2(r)) >= esp) {
        double mid1 = l + (r - l) / 3;
        double mid2 = r - (r - l) / 3;
        Point F1 = Fx2(mid1);
        Point F2 = Fx2(mid2);
        if (dist(E, F1) / R + dist(F1, D) / Q >= dist(E, F2) / R + dist(F2, D) / Q) l = mid1;
        else r = mid2;
    }
    Point F = Fx2(l);
    ans += dist(E, F) / R + dist(F, D) / Q;
    return ans;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> A.x >> A.y >> B.x >> B.y;
    cin >> C.x >> C.y >> D.x >> D.y;
    cin >> P >> Q >> R;

    double l = 0, r = 1;
    while (dist(Fx1(l), Fx1(r)) >= esp) {
        double mid1 = l + (r - l) / 3;
        double mid2 = r - (r - l) / 3;
        Point E1 = Fx1(mid1);
        Point E2 = Fx1(mid2);
        if (calc(E1) >= calc(E2)) l = mid1;
        else r = mid2;
    }
    Point E = Fx1(l);
    cout << fixed << setprecision(2) << calc(E) << '\n';
    return 0;
}
posted @ 2022-06-29 03:05  空白菌  阅读(79)  评论(0编辑  收藏  举报