zoukankan      html  css  js  c++  java
  • [ICPC2020南京I] Interested in Skiing

    [ICPC2020南京I] Interested in Skiing - dp,计算几何

    Description

    二维平面上有若干条线段和两条直线 x=-m, x=m 作为障碍,从 ((0,-infty)) 走到 ((0,infty)),不能碰到任何障碍。(y) 方向速度恒定为 (+v_y)(x) 方向速度可以随意调节,但其绝对值有一个上界 (a)。求最小的 (a) 是多少。

    Solution

    最优策略一定是经过若干条线段的端点,因此拿着所有端点做个 dp 即可,过程中需要用到判交,暴力判断即可,总体时间复杂度 (O(n^3))

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace geo
    {
    
    #define mp make_pair
    #define fi first
    #define se second
    #define pb push_back
        typedef double db;
        const db eps = 1e-6;
        const db pi = acos(-1);
        int sign(db k)
        {
            if (k > eps)
                return 1;
            else if (k < -eps)
                return -1;
            return 0;
        }
        int cmp(db p1, db p2) { return sign(p1 - p2); }
        int inmid(db p1, db p2, db p3) { return sign(p1 - p3) * sign(p2 - p3) <= 0; }
    
        struct point
        {
            db x, y;
            point operator+(const point &p1) const { return (point){p1.x + x, p1.y + y}; }
            point operator-(const point &p1) const { return (point){x - p1.x, y - p1.y}; }
            point operator*(db p1) const { return (point){x * p1, y * p1}; }
            point operator/(db p1) const { return (point){x / p1, y / p1}; }
            int operator==(const point &p1) const { return cmp(x, p1.x) == 0 && cmp(y, p1.y) == 0; }
            // 逆时针旋转
            point turn(db p1) { return (point){x * cos(p1) - y * sin(p1), x * sin(p1) + y * cos(p1)}; }
            point turn90() { return (point){-y, x}; }
            bool operator<(const point p1) const
            {
                int a = cmp(x, p1.x);
                if (a == -1)
                    return 1;
                else if (a == 1)
                    return 0;
                else
                    return cmp(y, p1.y) == -1;
            }
            db abs() { return sqrt(x * x + y * y); }
            db abs2() { return x * x + y * y; }
            db dis(point p1) { return ((*this) - p1).abs(); }
            point unit()
            {
                db w = abs();
                return (point){x / w, y / w};
            }
            void scan()
            {
                double p1, p2;
                cin >> p1 >> p2;
                x = p1;
                y = p2;
            }
            void print() { printf("%.11lf %.11lf
    ", x, y); }
            db getw() { return atan2(y, x); }
            point getdel()
            {
                if (sign(x) == -1 || (sign(x) == 0 && sign(y) == -1))
                    return (*this) * (-1);
                else
                    return (*this);
            }
            int getP() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) == -1); }
        };
        int inmid(point p1, point p2, point p3) { return inmid(p1.x, p2.x, p3.x) && inmid(p1.y, p2.y, p3.y); }
        db cross(point p1, point p2) { return p1.x * p2.y - p1.y * p2.x; }
        db dot(point p1, point p2) { return p1.x * p2.x + p1.y * p2.y; }
        db rad(point p1, point p2) { return atan2(cross(p1, p2), dot(p1, p2)); }
        // -pi -> pi
        int compareangle(point p1, point p2)
        {
            return p1.getP() < p2.getP() || (p1.getP() == p2.getP() && sign(cross(p1, p2)) > 0);
        }
        point proj(point p1, point p2, point q)
        { // q 到直线 p1,p2 的投影
            point k = p2 - p1;
            return p1 + k * (dot(q - p1, k) / k.abs2());
        }
        point reflect(point p1, point p2, point q) { return proj(p1, p2, q) * 2 - q; }
        int clockwise(point p1, point p2, point p3)
        { // p1 p2 p3 逆时针 1 顺时针 -1 否则 0
            return sign(cross(p2 - p1, p3 - p1));
        }
        int checkLL(point p1, point p2, point p3, point p4)
        { // 求直线 (L) 线段 (S)p1,p2 和 p3,p4 的交点
            return cmp(cross(p3 - p1, p4 - p1), cross(p3 - p2, p4 - p2)) != 0;
        }
        point getLL(point p1, point p2, point p3, point p4)
        {
            db w1 = cross(p1 - p3, p4 - p3), w2 = cross(p4 - p3, p2 - p3);
            return (p1 * w2 + p2 * w1) / (w1 + w2);
        }
        int intersect(db l1, db r1, db l2, db r2)
        {
            if (l1 > r1)
                swap(l1, r1);
            if (l2 > r2)
                swap(l2, r2);
            return cmp(r1, l2) == 1 && cmp(r2, l1) == 1;
        }
        int checkSS(point p1, point p2, point p3, point p4)
        {
            return intersect(p1.x, p2.x, p3.x, p4.x) && intersect(p1.y, p2.y, p3.y, p4.y) &&
                   sign(cross(p3 - p1, p4 - p1)) * sign(cross(p3 - p2, p4 - p2)) < 0 &&
                   sign(cross(p1 - p3, p2 - p3)) * sign(cross(p1 - p4, p2 - p4)) < 0;
        }
        db disSP(point p1, point p2, point q)
        {
            point p3 = proj(p1, p2, q);
            if (inmid(p1, p2, p3))
                return q.dis(p3);
            else
                return min(q.dis(p1), q.dis(p2));
        }
        db disSS(point p1, point p2, point p3, point p4)
        {
            if (checkSS(p1, p2, p3, p4))
                return 0;
            else
                return min(min(disSP(p1, p2, p3), disSP(p1, p2, p4)), min(disSP(p3, p4, p1), disSP(p3, p4, p2)));
        }
        int onS(point p1, point p2, point q) { return inmid(p1, p2, q) && sign(cross(p1 - q, p2 - p1)) == 0; }
        struct line
        {
            // p[0]->p[1]
            point p[2];
            line(point p1 = {0, 0}, point p2 = {0, 0})
            {
                p[0] = p1;
                p[1] = p2;
            }
            point &operator[](int k) { return p[k]; }
            int include(point k) { return sign(cross(p[1] - p[0], k - p[0])) > 0; }
            point dir() { return p[1] - p[0]; }
            line push()
            { // 向外 ( 左手边 ) 平移 eps
                const db eps = 1e-6;
                point delta = (p[1] - p[0]).turn90().unit() * eps;
                return {p[0] - delta, p[1] - delta};
            }
        };
        point getLL(line p1, line p2) { return getLL(p1[0], p1[1], p2[0], p2[1]); }
        int parallel(line p1, line p2) { return sign(cross(p1.dir(), p2.dir())) == 0; }
        int sameDir(line p1, line p2) { return parallel(p1, p2) && sign(dot(p1.dir(), p2.dir())) == 1; }
        int operator<(line p1, line p2)
        {
            if (sameDir(p1, p2))
                return p2.include(p1[0]);
            return compareangle(p1.dir(), p2.dir());
        }
        int checkpos(line p1, line p2, line p3) { return p3.include(getLL(p1, p2)); }
    
    }
    
    typedef geo::point vec2;
    typedef geo::line line;
    using geo::checkSS;
    
    bool cmp(const vec2 &lhs, const vec2 &rhs)
    {
        return lhs.y < rhs.y;
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int n, m;
        double vy;
        cin >> n >> m >> vy;
        vector<line> l(n + 2);
        for (int i = 1; i <= n; i++)
            l[i].p[0].scan(), l[i].p[1].scan();
        vector<vec2> p(2 * n + 2);
        p[0] = {0, -1e100};
        for (int i = 1; i <= n; i++)
            p[2 * i - 1] = l[i].p[0], p[2 * i] = l[i].p[1];
        p[2 * n + 1] = {0, 1e100};
        sort(p.begin(), p.end(), cmp);
        vector<double> f(2 * n + 2);
        for (int i = 1; i <= 2 * n + 1; i++)
        {
            f[i] = 1e100;
            if (abs(p[i].x) >= m)
                continue;
            for (int j = 0; j < i; j++)
            {
                if (p[i].y == p[j].y)
                    continue;
                int flag = 1;
                for (int k = 1; k <= n; k++)
                {
                    if (checkSS(l[k].p[0], l[k].p[1], p[j], p[i]))
                    {
                        flag = 0;
                        break;
                    }
                }
                if (flag)
                {
                    f[i] = min(f[i], max(f[j], abs(p[i].x - p[j].x) / (p[i].y - p[j].y + 1e-18)));
                }
            }
        }
        if (f[2 * n + 1] <= 1e20)
            cout << fixed << setprecision(16) << f[2 * n + 1] * vy << endl;
        else
            cout << -1 << endl;
    }
    
    
  • 相关阅读:
    洛谷 P4318 完全平方数 二分+容斥
    洛谷 P4899 [IOI2018] werewolf 狼人 克鲁斯卡尔重构树+主席树
    洛谷 P3997 [SHOI2013]扇形面积并 线段树
    洛谷 P3268 [JLOI2016]圆的异或并 扫描线
    OI有关 学习网站
    Linux命令基础——stat-readdir-dup2
    Linux命令基础——makefile+gdb+IO
    Linux命令基础——vim+gcc+ibrary
    Linux命令基础——常用命令
    MFC学习笔记——07-MFC_20day
  • 原文地址:https://www.cnblogs.com/mollnn/p/14598077.html
Copyright © 2011-2022 走看看