2023湖南

发布时间 2023-04-06 17:43:27作者: Kidding_Ma
C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

using Real = double;
using Point = complex<Real>;

#define x real
#define y imag

constexpr Real eps = 1E-9;

int sign(const Real &x) {
    return x < -eps ? -1 : x > eps ? 1 : 0;
}

struct Line {
    Point a, b;
    Line() {}
    Line(const Point &a, const Point &b) : a(a), b(b) {}
};

struct Segment : Line {
    Segment() = default;
    using Line::Line;
    Real len() const {
        return abs(a - b);
    }
};

Real cross(const Point &a, const Point &b) {
    return (conj(a) * b).y();
}

Real dot(const Point &a, const Point &b) {
    return (conj(a) * b).x();
}

int onLeft(const Point &p, const Line &l) {
    return sign(cross(l.b - l.a, p - l.a));
}

bool collinear(const Line &l1, const Line &l2) {
    return sign(cross(l1.b - l1.a, l2.b - l2.a)) == 0 && sign(cross(l1.b - l1.a, l1.b - l2.a)) == 0;
}

bool intersect(const Segment &s1, const Segment &s2) {
    return onLeft(s2.a, s1) * onLeft(s2.b, s1) <= 0 && onLeft(s1.a, s2) * onLeft(s1.b, s2) <= 0;
}

bool onSegment(const Point &p, const Segment &s) {
    return sign(cross(p - s.a, s.b - s.a)) == 0 && sign(dot(p - s.a, p - s.b)) <= 0;
}

// -1 : on, 0 : out, 1 : in
int contains(const Point &p, const vector<Point> &g) {
    int gsz = g.size();
    bool in = false;
    for(int i = 0; i < gsz; i++) {
        Point a = g[i] - p, b = g[(i + 1) % gsz] - p;
        if (a.y() > b.y()) swap(a, b);
        if (a.y() <= 0 && 0 < b.y() && cross(a, b) < 0) in = !in;
        if (cross(a, b) == 0 && dot(a, b) <= 0) return -1;
    }
    return in ? 1 : 0;
}

void solve(int n) {
    vector<Point> a(n);
 
    for (int i = 0; i < n; i++) {
        int x, y;
        cin >> x >> y;
        a[i] = Point(x, y);
    }

    int x, y;
    cin >> x >> y;
    Point s = Point(x, y);
    cin >> x >> y;
    Point t = Point(x, y);

    auto check = [&](const Segment &S) {
        for (int i = 0; i < n; i++) {
            Segment T(a[i], a[(i + 1) % n]);
            if (collinear(S, T)) {
                continue;
            }
            if (intersect(S, T) && !onSegment(S.a, T) && !onSegment(S.b, T)) {
                return false;
            }
        }
        Point mid = (S.a + S.b) / 2.0;
        if (contains(mid, a) == 1){
            return false;
        }
        return true;
    };

    vector<Point> P;
    P.push_back(s);
    P.push_back(t);
    for (int i = 0; i < n; i++) {
        P.push_back(a[i]);
    }

    int m = P.size();
    vector<vector<pair<int, double>>> g(m);

    for (int i = 0; i < m; i++) {
        for (int j = i + 1; j < m; j++) {
            Segment S(P[i], P[j]);
            if (check(S)) {
                g[i].push_back({j, S.len()});
                g[j].push_back({i, S.len()});
            }
        }
    }

    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> q;
    vector<int> vis(m);
    vector<double> dis(m, 1E9);
    dis[0] = 0;
    q.push({dis[0], 0});
    while (!q.empty()) {
        double u = q.top().first;
        int v = q.top().second;
        q.pop();
        if (v == 1) {
            cout << dis[1] << '\n';
            return;
        }
        if (!vis[v]) {
            vis[v] = 1;
            for (auto d : g[v]) {
                int x = d.first;
                double w = d.second;
                if (dis[x] > dis[v] + w) {
                    dis[x] = dis[v] + w;
                    q.push({dis[x], x});
                }
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cout << fixed << setprecision(15);

    int n;
    while (cin >> n) {
        solve(n);
    }
    
    return 0;
}