码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3400(Line belt 三分套娃)

时间:2020-05-21 11:49:06      阅读:38      评论:0      收藏:0      [点我收藏+]

标签:strong   sqrt   printf   ++   point   namespace   lin   print   pac   

Line belt

思路

我们假定在\(A, B\)上选取点\(E\),在\(C, D\)上选取点\(F\),我们的移动路径是\(A -> E -> F -> D\)

当我们确定\(E\)点时,不难发现\(dis(E -> F + F -> D)\)是一个凹函数,具有极小值。

当我们确定\(F\)点时不难发现\(dis(A -> E + E -> F)\)也是一个凹函数,具有极小值。

这两段函数连接起来,不难发现也是一个凹函数,具有极小值。

这就好像是一个套娃的三分了,我们可以通过确定\(E\)点,然后去找到\(min\ dis(E -> F + F -> D)\)

然后由于函数具有整体的凹性,我们只要通过基础的三分来三分点\(E\),就能确定最后的答案。

具体有一些细节在代码中。

代码

#include <bits/stdc++.h>

using namespace std;

const double eps = 1e-6;

double P, Q, R;

struct point {
    double x, y;
    point(double a = 0.0, double b = 0.0) : x(a), y(b) {};
}A, B, C, D, E, F;

double dis(point a, point b) {
    //这里我也是看了评论,不加eps就wa,
    //好像如果不加eps会导致答案偏小。
    return sqrt(eps + (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double calc2(double x) {
    //通过长度和向量确定F点坐标,
    //一定要注意坐标C, D的前后顺序,
    F = point(C.x + (x / dis(C, D)) * (D.x - C.x), C.y + (x / dis(C, D)) * (D.y - C.y));
    //cost(E -> F + F -> D)
    return (dis(E, F) / R) + ((dis(C, D) - x) / Q);
}

double calc1(double x) {
    //通过长度和向量来确定E点的坐标。
    //一定要注意坐标A, B的前后顺序,
    E = point(A.x + (x / dis(A, B)) * (B.x - A.x), A.y + (x / dis(A, B)) * (B.y - A.y));
    double l = 0, r = dis(C, D);//从长度三分F点。
    for(int i = 0; i < 100; i++) {
        double lmid = l + (r - l) / 3;
        double rmid = r - (r - l) / 3;
        if(calc2(lmid) >= calc2(rmid))  l = lmid;
        else r = rmid;
    }
    //calc2 + cost(A -> E)。
    return calc2(l) + (x / P);
    
}

int main() {
    // freopen("in.txt", "r", stdin);
    int t;  scanf("%d", &t);
    while(t--) {
        scanf("%lf %lf", &A.x, &A.y);
        scanf("%lf %lf", &B.x, &B.y);
        scanf("%lf %lf", &C.x, &C.y);
        scanf("%lf %lf", &D.x, &D.y);
        scanf("%lf %lf %lf", &P, &Q, &R);
        double l = 0, r = dis(A, B);//从长度三分E点。
        // cout << l << " " << r << endl;
        for(int i = 0; i < 100; i++) {
            double lmid = l + (r - l) / 3;
            double rmid = r - (r - l) / 3;
            if(calc1(lmid) >= calc1(rmid))  l = lmid;
            else    r = rmid;
        }
        // cout << l << " " << r << endl;
        printf("%.2f\n", calc1(l));
        // puts("");
    }
    return 0;
}

一组样例及答案

8
0 0 4 1
4 1 0 2
8 8 1
0 0 0 100
100 0 100 100
2 2 1
8 0 23 8
4 2 91 0
4 9 10
0 0 2 2
0 2 2 0
4 3 1
1 8 1000 10
0 689 10 1000
90 1 20
4 9 4 20
4 41 4 60
4 4 1
4 9 4 20
4 91 4 60
4 3 1
0 5 8 5
2 5 4 0
6 9 3


1.03
136.60
8.30
0.83
49.60
28.50
42.75
0.93

HDU 3400(Line belt 三分套娃)

标签:strong   sqrt   printf   ++   point   namespace   lin   print   pac   

原文地址:https://www.cnblogs.com/lifehappy/p/12929612.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!