1. 程式人生 > >HDU-3400 Line belt 計算幾何 三分

HDU-3400 Line belt 計算幾何 三分

HDU-3400 Line belt

題意:給定兩條線段AB和CD, 在AB上的速度為p, CD上的速度為q,其他地方的速度為r, 求從A->D的所需的最短時間。
分析: AB和CD上分別有一個點是滿足最小條件的, 滿足凸函式性質,可以對AB和CD區間進行分別三分求解, 詳情見程式碼。
程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const double eps = 1e-10;
struct Point
{
    double x, y;
    Point() {}
    Point(double _x, double _y)
    {
        x = _x;
        y = _y;
    }
    Point mid(Point b)
    {
        return Point((x + b.x) / 2, (y + b.y) / 2);
    }
    double distance(Point p)
    {
        return hypot(x - p.x, y - p.y);
    }
};
Point A, B, C, D;
double P, Q, R;
//CD三分
double solve(Point x)
{
    Point l, r, mid, midmid;
    l = C, r = D;
    double dis1, dis2;
    while (r.distance(l) > eps)
    {
        mid = l.mid(r);
        midmid = mid.mid(r);

        dis1 = x.distance(mid) / R + mid.distance(D) / Q;
        dis2 = x.distance(midmid) / R + midmid.distance(D) / Q;
        if (dis1 > dis2)
        {
            l = mid;
        }
        else
        {
            r = midmid;
        }
    }
    return x.distance(l) / R + l.distance(D) / Q;
}
//AB三分
double solve()
{
    Point l, r, mid, midmid;
    l = A, r = B;
    double dis1, dis2;
    while (r.distance(l) > eps)
    {
        mid = l.mid(r);
        midmid = mid.mid(r);

        dis1 = A.distance(mid) / P + solve(mid);
        dis2 = A.distance(midmid) / P + solve(midmid);

        if (dis1 > dis2)
        {
            l = mid;
        }
        else
        {
            r = midmid;
        }
    }
    return A.distance(l) / P + solve(l);
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y);
        scanf("%lf%lf%lf%lf", &C.x, &C.y, &D.x, &D.y);
        scanf("%lf%lf%lf", &P, &Q, &R);
        printf("%.2f\n", solve());
    }
    return 0;
}