zoukankan      html  css  js  c++  java
  • HDU 3400(Line belt 三分套娃)

    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
    ", 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
    
  • 相关阅读:
    js总结 |数组重复问题
    前端Js自定义相机取景框
    nodejs+mongodb运用
    使用MongoDB
    总结 |异步/非阻塞的处理方式
    npm与依赖包
    js总结 |JS深度拷贝的方法
    js笔记 |整洁代码技巧
    微信支付——介入指引
    2021最全测试资源合集(已更新至2021.03.09,关注测试生财公众号,享受独家爆料)
  • 原文地址:https://www.cnblogs.com/lifehappy/p/12929612.html
Copyright © 2011-2022 走看看