QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#339750#5479. Traveling Salesperson in an Islandlmf_upWA 42ms4248kbC++2038.4kb2024-02-27 20:50:362024-02-27 20:50:36

Judging History

你现在查看的是最新测评结果

  • [2024-02-27 20:50:36]
  • 评测
  • 测评结果:WA
  • 用时:42ms
  • 内存:4248kb
  • [2024-02-27 20:50:36]
  • 提交

answer

#include<bits/stdc++.h>

#define cp const point &
#define cl const line &
#define cc const circle &
#define LD long double
std::mt19937 rnd(time(0));
const LD eps = 1e-12;
const LD pi = std::numbers::pi;
const LD INF = 1e9;

int sgn(LD x)
{
    return x > eps ? 1 : (x < -eps ? -1 : 0);
}

LD sqr(LD x)
{ return x * x; }

struct point
{
    LD x, y;

    point operator+(cp a) const
    { return {x + a.x, y + a.y}; }

    point operator-(cp a) const
    { return {x - a.x, y - a.y}; }

    point operator*(LD t) const
    { return {x * t, y * t}; }

    point operator/(LD t) const
    { return {x / t, y / t}; }

    point rot(LD t) const
    { return {(LD) (x * cos(t) - y * sin(t)), (LD) (x * sin(t) + y * cos(t))}; }

    point rot90() const
    { return {-y, x}; }

    point rot270() const
    {return point(y,-x);}

    LD len2() const
    { return x * x + y * y; }

    LD len() const
    { return sqrtl(x * x + y * y); }

    point unit() const
    {
        LD d = len();
        return {(LD) (x / d), (LD) (y / d)};
    }

    int on_up()//b不判(0,0)
    {
        return sgn(y) == 1 || (sgn(y) == 0 && sgn(x) <0);
    }

    void print()
    {
        std::cout << x << ' ' << y << std::endl;
    }

    void read()
    {
        int xx, yy;
        std::cin >> xx >> yy;
        x = xx, y = yy;
    }

    friend bool operator<(cp a, cp b)
    {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }

    friend bool operator>(cp a, cp b)
    {
        return a.x == b.x ? a.y > b.y : a.x > b.x;
    }
};

LD dot(cp a, cp b);

bool operator==(cp a, cp b)
{
    return !sgn(dot(a - b, a - b));
//    return !sgn(a.x-b.x)&&!(a.y-b.y); //看题目有无给出确定两实数相等的eps
}

LD dis(cp a, cp b)//两点距离
{
    return sqrtl(sqr(a.x - b.x) + sqr(a.y - b.y));
}

LD dot(cp a, cp b)//点乘
{
    return a.x * b.x + a.y * b.y;
}

LD det(cp a, cp b)//叉乘
{
    return a.x * b.y - b.x * a.y;
}
LD deg(point a,point b)
{
    a=a.unit(),b=b.unit();
    LD d=dis(a,b);
    return 2*asinl(d/2);
}
bool  turn_left_strict(cp a,cp b,cp c)
{
    return sgn(det(b-a,c-a))>0;
}
bool turn_left(cp a, cp b, cp c)
{
    return sgn(det(b - a, c - a)) >=0;
}

struct line
{
    point s, t;

    line()
    {}

    line(point a, point b) : s(a), t(b)
    {}

    void read()
    {
        s.read(), t.read();
    }

    void print()
    {
        s.print(), std::cout << ' ', t.print();
    }

};

struct circle
{
    point c;
    LD r;

    circle()
    {}

    circle(point C, LD R)
    { c = C, r = R; }
};

bool in_circle(cp a, cc b)
{
    return sgn((b.c - a).len() - b.r) <= 0;
}

circle make_circle(point u, point v)
{
    point p = (u + v) / 2;
    return circle(p, (u - p).len());
}

circle make_circle(cp a, cp b, cp c)
{
    point p = b - a, q = c - a;
    point s(dot(p, p) / 2, dot(q, q) / 2);
    LD d = det(p, q);
    p = point(det(s, point(p.y, q.y)), det(point(p.x, q.x), s)) / d;
    return circle(a + p, p.len());
}

circle min_circle(std::vector<point> p)
{
    circle ret(p[0], 0);
    std::shuffle(p.begin(), p.end(), rnd);
    int len = p.size();
    for (int i = 0; i < len; i++)
        if (!in_circle(p[i], ret))
        {
            ret = circle(p[i], 0);
            for (int j = 0; j < i; j++)
                if (!in_circle(p[j], ret))
                {
                    ret = make_circle(p[j], p[i]);
                    for (int k = 0; k < j; ++k)
                        if (!in_circle(p[k], ret))
                            ret = make_circle(p[i], p[j], p[k]);
                }
        }
    return ret;
}

LD get_rad(point a, point b)
{
    if (a == point(0, 0) || b == point(0, 0))
        return 0;
    else
    {
        return acosl(dot(a, b) / (a.len() * b.len()));
    }
}

bool same_dir(cl a, cl b)//判断方向是否一致
{
    return sgn(det(b.t - b.s, a.t - a.s)) == 0 && sgn(dot(b.t - b.s, a.t - a.s)) > 0;
}

bool point_on_line(cp a, cl l)//判断点是否在直线上
{
    return sgn(det(a - l.s, l.t - l.s)) == 0;
}

bool point_on_segment(cp a, cl l)//判断点是否在线段上
{
    return point_on_line(a, l) && sgn(dot(l.s - a, l.t - a)) <= 0;//(<=代表可以端点
}

bool two_side(cp a, cp b, cl c)//判断两个点是否在线段的两边
{
    return sgn(det(a - c.s, c.t - c.s)) * sgn(det(b - c.s, c.t - c.s)) < 0;
}

bool intersect_judge_strict(cl a, cl b)
{
    return two_side(a.s, a.t, b) && two_side(b.s, b.t, a);
}

bool intersect_judge(cl a, cl b)
{//判断两个线段是否相交
    if (point_on_segment(a.s, b) || point_on_segment(a.t, b) || point_on_segment(b.s, a) ||
        point_on_segment(b.t, a))
        return true;
    return intersect_judge_strict(a, b);
}


point line_intersect(cl a, cl b)
{//得到两线段的交点
    LD s1 = det(a.t - a.s, b.s - a.s);
    LD s2 = det(a.t - a.s, b.t - a.s);
    return (b.s * s2 - b.t * s1) / (s2 - s1);
}

bool point_on_ray(cp a, cl b)
{//判断点是否在射线上
    return sgn(det(a - b.s, b.t - b.s)) == 0 && sgn(dot(a - b.s, b.t - b.s)) >= 0;
}

bool ray_intersect_judge(line a, line b)//判断两射线是否相交
{
    LD s1, s2;
    s1 = det(a.t - a.s, b.s - a.s);
    s2 = det(a.t - a.s, b.t - a.s);
    if (sgn(s1) == 0 && sgn(s2) == 0)
        return sgn(dot(a.t - a.s, b.s - a.s)) >= 0 || sgn(dot(b.t - b.s, a.s - b.s));
    if (!sgn(s1 - s2) || sgn(s1) == sgn(s2 - s1))return 0;
    std::swap(a, b);
    s1 = det(a.t - a.s, b.s - a.s);
    s2 = det(a.t - a.s, b.t - a.s);
    return sgn(s1) != sgn(s2 - s1);
}

LD point_to_line(cp a, cl b)
{//点到直线的距离
    return abs(det(b.t - b.s, a - b.s)) / dis(b.s, b.t);
}

point project_to_line(cp a, cl b)
{//得到点在线上的投影
    return b.s + (b.t - b.s) * (dot(a - b.s, b.t - b.s) / (b.t - b.s).len2());
}

LD point_to_segment(cp a, cl b)
{//点到线段的距离
    if (b.s == b.t)
        return dis(a, b.s);
    if (sgn(dot(b.s - a, b.t - b.s)) * sgn(dot(b.t - a, b.t - b.s)) <= 0)
        return abs(det(b.t - b.s, a - b.s)) / dis(b.s, b.t);
    return std::min(dis(a, b.s), dis(a, b.t));
}

std::vector<point> line_circle_intersect(cl a, cc b)//线与圆的交点
{//返回线与圆的交点
    if (sgn(point_to_segment(b.c, a) - b.r) > 0)
        return std::vector<point>();
    LD x = sqrtl(sqr(b.r) - sqr(point_to_line(b.c, a)));
    return std::vector<point>(
            {project_to_line(b.c, a) + (a.s - a.t).unit() * x, project_to_line(b.c, a) - (a.s - a.t).unit() * x});
}

LD circle_intersect_area(cc a, cc b)//求两个圆相交区域的面积
{
    LD d = dis(a.c, b.c);
    if (sgn(d - (a.r + b.r)) >= 0)return 0;
    if (sgn(d - abs(a.r - b.r)) <= 0)
    {
        LD r = std::min(a.r, b.r);
        return r * r * pi;
    }
    LD x = (d * d + a.r * a.r - b.r * b.r) / (2 * d),
            t1 = acosl(std::min((LD) 1, std::max((LD) -1, x / a.r))),
            t2 = acosl(std::min((LD) 1, std::max((LD) -1, (d - x) / b.r)));
    return sqr(a.r) * t1 + sqr(b.r) * t2 - d * a.r * sinl(t1);
}

std::vector<point> circle_intersect(cc a, cc b)//求两个圆的交
{
    if (a.c == b.c || sgn(dis(a.c, b.c) - a.r - b.r) > 0 || sgn(dis(a.c, b.c) - abs(a.r - b.r)) < 0)
        return {};
    point r = (b.c - a.c).unit();
    LD d = dis(a.c, b.c);
    LD x = ((sqr(a.r) - sqr(b.r)) / d + d) / 2;
    LD h = sqrtl(sqr(a.r) - sqr(x));
    if (sgn(h) == 0)return {a.c + r * x};
    return {a.c + r * x + r.rot90() * h, a.c + r * x - r.rot90() * h};
}

std::vector<point> tangent(cp a, cc b)//求一个点关于圆的切线
{
    circle p = make_circle(a, b.c);
    return circle_intersect(p, b);
}

std::vector<line> extangent(cc a, cc b)//求两圆的外切线
{
    std::vector<line> ret;
    if (sgn(dis(a.c, b.c) - abs(a.r - b.r)) <= 0)return ret;
    if (sgn(a.r - b.r) == 0)
    {
        point dir = b.c - a.c;
        dir = (dir * a.r / dir.len()).rot90();
        ret.push_back(line(a.c + dir, b.c + dir));
        ret.push_back(line(a.c - dir, b.c - dir));
    }
    else
    {
        point p = (b.c * a.r - a.c * b.r) / (a.r - b.r);
        std::vector pp = tangent(p, a), qq = tangent(p, b);
        if (pp.size() == 2 && qq.size() == 2)
        {
            if (sgn(a.r - b.r) < 0)
                std::swap(pp[0], pp[1]), std::swap(qq[0], qq[1]);
            ret.push_back(line(pp[0], qq[0]));
            ret.push_back(line(pp[1], qq[1]));
        }
    }
    return ret;
}

std::vector<line> intangent(cc a, cc b)//求两圆的内切线
{
    std::vector<line> ret;
    point p = (b.c * a.r + a.c * b.r) / (a.r + b.r);
    std::vector pp = tangent(p, a), qq = tangent(p, b);
    if (pp.size() == 2 && qq.size() == 2)
    {
        ret.push_back(line(pp[0], qq[0]));
        ret.push_back(line(pp[1], qq[1]));
    }
    return ret;
}

std::vector<point> cut(const std::vector<point> &c, line p)
{
    std::vector<point> ret;
    if (c.empty())return ret;
    int len = c.size();
    for (int i = 0; i < len; i++)
    {
        int j = (i + 1) % len;
        if (turn_left(p.s, p.t, c[i]))ret.push_back(c[i]);
        if (two_side(c[i], c[j], p))
            ret.push_back(line_intersect(p, line(c[i], c[j])));
    }
    return ret;
}

std::vector<point> convex_hull(std::vector<point> a)
{//凸包,字典序
    int n = (int) a.size(), cnt = 0;
    if (n < 2) return a;
    std::sort(a.begin(), a.end()); // less<pair>
    std::vector<point> ret;
    for (int i = 0; i < n; ++i)
    {
        while (cnt > 1
               && !turn_left(ret[cnt - 1], a[i], ret[cnt - 2]))
            --cnt, ret.pop_back();
        ++cnt, ret.push_back(a[i]);
    }
    int fixed = cnt;
    for (int i = n - 2; i >= 0; --i)
    {
        while (cnt > fixed
               && !turn_left(ret[cnt - 1], a[i], ret[cnt - 2]))
            --cnt, ret.pop_back();
        ++cnt, ret.push_back(a[i]);
    }
    ret.pop_back();
    return ret;
}

std::vector<point> minkovski(std::vector<std::vector<point>> a)
{
    if (a[0].size() == 1)
        return a[1];
    if (a[1].size() == 1)
        return a[0];
    for (int i = 0; i < 2; i++)a[i].push_back(a[i].front());
    int i[2] = {0, 0}, len[2] = {(int) a[0].size() - 1, (int) a[1].size() - 1};
    std::vector<point> ret;
    ret.push_back(a[0][0] + a[1][0]);
    do
    {
        int d = sgn(det(a[1][i[1] + 1] - a[1][i[1]], a[0][i[0] + 1] - a[0][i[0]])) >= 0;
        ret.push_back(a[d][i[d] + 1] - a[d][i[d]] + ret.back());
        i[d] = (i[d] + 1) % len[d];
    }
    while (i[0] || i[1]);
    return ret;
}

struct Convex
{
    int n;
    std::vector<point> a, upper, lower;
    std::map<point, int> mp;

    Convex(std::vector<point> _a) : a(_a)
    {
        n = a.size();
        int k = 0;
        for (int i = 1; i < n; i++)if (a[k] < a[i])k = i;
        for (int i = 0; i <= k; i++) lower.push_back(a[i]);
        for (int i = k; i < n; i++) upper.push_back(a[i]);
        upper.push_back(a[0]);
    }

    void pre_to_check_point()
    {
        for (int i = 0; i < n; i++)
            mp[a[i]] = i;
    }

    std::pair<LD, int> get_tan(std::vector<point> &con, point vec)
    {
        int l = 0, r = (int) con.size() - 2;
        for (; l + 1 < r;)
        {
            int mid = (l + r) / 2;
            if (sgn(det(con[mid + 1] - con[mid], vec)) > 0)r = mid;
            else l = mid;
        }
        return std::max(std::make_pair(det(vec, con[r]), r), std::make_pair(det(vec, con[0]), 0));
    }

    void upd_tan(cp p, int id, int &i0, int &i1)//辅助函数
    {
//        if (i0 == -1) i0 = id;
        if ((det(a[i0] - p, a[id] - p)) > 0) i0 = id;
//        if (i1 == -1) i1 = id;
        if ((det(a[i1] - p, a[id] - p)) < 0) i1 = id;
    }

    void search(int l, int r, point p, int &i0, int &i1)//辅助函数
    {
        if (l == r)return;
        upd_tan(p, l % n, i0, i1);
        int sl = sgn(det(a[l % n] - p, a[(l + 1) % n] - p));
        for (; l + 1 < r;)
        {
            int mid = (l + r) / 2;
            int smid = sgn(det(a[mid % n] - p, a[(mid + 1) % n] - p));
            if (smid == sl)l = mid;
            else r = mid;
        }
        upd_tan(p, r % n, i0, i1);
    }

    int search(point u, point v, int l, int r)//辅助函数
    {
        int sl = sgn(det(v - u, a[l % n] - u));
        for (; l + 1 < r;)
        {
            int mid = (l + r) / 2;
            int smid = sgn(det(v - u, a[mid % n] - u));
            if (smid == sl) l = mid;
            else r = mid;
        }
        return l % n;
    }

    //判定点是否在凸包内,在边界返回true
    bool contain(point p)
    {
        if (p.x < lower[0].x || p.x > lower.back().x)return false;
        int id = std::lower_bound(lower.begin(), lower.end(), point(p.x, -INF)) - lower.begin();
        if (lower[id].x == p.x)
        {
            if (lower[id].y > p.y)return false;
        }
        else if (det(lower[id - 1] - p, lower[id] - p) < 0)
            return false;
        id = std::lower_bound(upper.begin(), upper.end(), point(p.x, INF), std::greater<point>()) - upper.begin();
        if (upper[id].x == p.x)
        {
            if (upper[id].y < p.y)return false;
        }
        else if (det(upper[id - 1] - p, upper[id] - p) < 0)
            return false;
        return true;
    }

    int contain_strict(point p)//0代表在外面 1代表在里面 2代表在边上 3代表在点上
    {
        if (p.x < lower[0].x || p.x > lower.back().x)return 0;
        int id = std::lower_bound(lower.begin(), lower.end(), point(p.x, -INF)) - lower.begin();
        if (lower[id].x == p.x)
        {
            if (lower[id].y > p.y)return 0;
            else if (sgn(lower[id].y - p.y) == 0) return 3;
            else if (id + 1 < lower.size() && lower[id + 1].x == p.x && p.y < lower[id + 1].y)
                return 2;
            else if (id + 1 < lower.size() && lower[id + 1].x == p.x && p.y == lower[id + 1].y)
                return 3;
        }
        else if (det(lower[id - 1] - p, lower[id] - p) < 0)
            return 0;
        else if (sgn(det(lower[id - 1] - p, lower[id] - p)) == 0)
            return 2;
        id = std::lower_bound(upper.begin(), upper.end(), point(p.x, INF), std::greater<point>()) - upper.begin();
        if (upper[id].x == p.x)
        {
            if (upper[id].y < p.y)return 0;
            else if (upper[id].y == p.y)return 3;
            else if (id + 1 < upper.size() && upper[id + 1].x == p.x && p.y > upper[id + 1].y)
                return 2;
            else if (id + 1 < upper.size() && upper[id + 1].x == p.x && p.y == upper[id + 1].y)
                return 3;
        }
        else if (det(upper[id - 1] - p, upper[id] - p) < 0)
            return 0;
        else if (sgn(det(upper[id - 1] - p, upper[id] - p)) == 0)
            return 2;
        return 1;
    }

    bool get_tan(point p, int &i0, int &i1)
    {// 求点 p 关于凸包的两个切点, 如果在凸包外则有序返回编号, 共线的多个切点返回任意一个, 否则返回 false
        i0 = i1 = 0;
        int id = int(std::lower_bound(lower.begin(), lower.end(), p) - lower.begin());
        search(0, id, p, i0, i1);
        search(id, (int) lower.size(), p, i0, i1);
        id = int(std::lower_bound(upper.begin(), upper.end(), p, std::greater<point>()) - upper.begin());
        search((int) lower.size() - 1, (int) lower.size() - 1 + id, p, i0, i1);
        search((int) lower.size() - 1 + id, (int) lower.size() - 1 + (int) upper.size(), p, i0, i1);
        return true;
    }

    bool my_get_tan(point p, int &i0, int &i1)//自己魔改,常数大,可求点在凸包上的切线
    {
        if (p.x < lower[0].x || p.x > lower.back().x)
        {
            get_tan(p, i0, i1);
            return true;
        }
        int id = std::lower_bound(lower.begin(), lower.end(), point(p.x, -INF)) - lower.begin();
        if (lower[id].x == p.x)
        {
            if (lower[id].y > p.y)
            {
                get_tan(p, i0, i1);
                return true;
            }
            else if (sgn(lower[id].y - p.y) == 0)
            {
                i0 = (id - 1 + n) % n, i1 = (id + 1) % n;
                return true;
            }
            else if (id + 1 < lower.size() && lower[id + 1].x == p.x && p.y < lower[id + 1].y)
            {
                i0 = id, i1 = (id + 1) % n;
                return true;
            }
            else if (id + 1 < lower.size() && lower[id + 1].x == p.x && p.y == lower[id + 1].y)
            {
                i0 = id, i1 = (id + 2) % n;
                return true;
            }
        }
        else if (det(lower[id - 1] - p, lower[id] - p) < 0)
        {
            get_tan(p, i0, i1);
            return true;
        }
        else if (sgn(det(lower[id - 1] - p, lower[id] - p)) == 0)
        {
            i0 = (id - 1 + n) % n, i1 = id;
            return true;
        }
        id = std::lower_bound(upper.begin(), upper.end(), point(p.x, INF), std::greater<point>()) - upper.begin();
        if (upper[id].x == p.x)
        {
            if (upper[id].y < p.y)
            {
                get_tan(p, i0, i1);
                return true;
            }
            else if (upper[id].y == p.y)
            {
                i0 = id + lower.size() - 1;
                i1 = (i0 + 1 + n) % n;
                i0 = (i0 + n - 1) % n;
                return true;
            }
            else if (id + 1 < upper.size() && upper[id + 1].x == p.x && p.y > upper[id + 1].y)
            {
                i0 = id + lower.size() - 1;
                i1 = (i0 + 1) % n;
                i0 = (i0 + n) % n;
                return true;
            }
            else if (id + 1 < upper.size() && upper[id + 1].x == p.x && p.y == upper[id + 1].y)
            {
                i0 = n - 1, i1 = 1;
                return true;
            }
        }
        else if (det(upper[id - 1] - p, upper[id] - p) < 0)
        {
            get_tan(p, i0, i1);
            return true;
        }
        else if (sgn(det(upper[id - 1] - p, upper[id] - p)) == 0)
        {
            i0 = (id + lower.size() - 1 + n) % n;
            i1 = (i0 - 1 + n) % n;
            std::swap(i0, i1);
            return true;
        }
        return false;
    }

    // 求凸包上和向量 vec 叉积最大的点, 返回编号, 共线的多个切点返回任意一个
    int get_tan(point vec)
    {
        std::pair<LD, int> ret = get_tan(upper, vec);
        ret.second = (ret.second + (int) lower.size() - 1) % n;
        ret = std::max(ret, get_tan(lower, vec));
        return ret.second;
    }

    bool my_judge_intersect_segment(cp u, cp v)//判断线段与凸包是否有严格相交,即有无穿过内部,默认起点和终点不在凸包内部了
    {
        int u1, u2;
        my_get_tan(u, u1, u2);
        if (!turn_left(u, a[u2], v) || !turn_left(u, v, a[u1]))
            return false;
        my_get_tan(v, u1, u2);
        if (!turn_left(v, a[u2], u) || !turn_left(v, u, a[u1]))
            return false;
        return true;
    }
    // 求凸包和直线 u,v 的交点, 如果无严格相交返回 false. 如果有则是和 (i,next(i)) 的交点, 两个点无序, 交在点上不确定返回前后两条线段其中之一

    bool get_inter(point u, point v, int &i0, int &i1)
    {
        int p0 = get_tan(u - v), p1 = get_tan(v - u);
        if (sgn(det(v - u, a[p0] - u)) * sgn(det(v - u, a[p1] - u)) < 0)
        {
            if (p0 > p1)std::swap(p0, p1);
            i0 = search(u, v, p0, p1);
            i1 = search(u, v, p1, p0 + n);
            return true;
        }
        else return false;
    }
};

bool in_polygon(cp p, const std::vector<point> &po)//判断点是否在多边形里
{
    int n = (int) po.size();
    int cnt = 0;
    for (int i = 0; i < n; i++)
    {
        point a = po[i], b = po[(i + 1) % n];
        if (point_on_segment(p, line(a, b)))return true;
        int x = sgn(det(p - a, b - a)), y = sgn(a.y - p.y), z = sgn(b.y - p.y);
        if (x > 0 && y <= 0 && z > 0)++cnt;
        if (x < 0 && z <= 0 && y > 0)--cnt;

    }
    return cnt != 0;
}

bool In_Polygon(cp P, std::vector<point> &polygon)//判断点是否在多边形里面,射线法O(n)
{
    bool flag = false; //相当于计数
    point P1, P2; //多边形一条边的两个顶点
    int n = polygon.size();
    for (int i = 0, j = n - 1; i < n; j = i++)
    {
        //polygon[]是给出多边形的顶点
        P1 = polygon[i];
        P2 = polygon[j];
        if (point_on_segment(P, line(P1, P2)))return true;
        //前一个判断min(P1.y,P2.y)<P.y<=max(P1.y,P2.y)
        //这个判断代码我觉得写的很精妙 我网上看的 应该是大神模版
        //后一个判断被测点 在 射线与边交点 的左边
        if ((sgn(P1.y - P.y) > 0 != sgn(P2.y - P.y) > 0) &&
            sgn(P.x - (P.y - P1.y) * (P1.x - P2.x) / (P1.y - P2.y) - P1.x) < 0)
            flag = !flag;
    }
    return flag;
}

std::vector<point> Minkovski(std::vector<std::vector<point>> a)//可处理退化成线段的凸包
{                                                            //闵可夫斯基和
    std::vector<point> S;
    int n = a[0].size(), m = a[1].size();
    std::vector<point> A(n), B(m);
    for (int i = 0; i < n - 1; i++) A[i] = a[0][i + 1] - a[0][i];
    A[n - 1] = a[0][0] - a[0][n - 1];
    for (int i = 0; i < m - 1; i++) B[i] = a[1][i + 1] - a[1][i];
    B[m - 1] = a[1][0] - a[1][m - 1];                                                             //将两个凸包上的边向量都存入a,b中
    S.push_back(a[0][0] + a[1][0]);
    int p1 = 0, p2 = 0;
    while (p1 < n && p2 < m)
    {
        LD d = det(A[p1], B[p2]);
        if (d > 0)
            S.push_back(S.back() + A[p1++]);
        else if (d < 0)
            S.push_back(S.back() + B[p2++]);
        else
        {
            if (dot(A[p1], B[p1]) >= 0)
                S.push_back(S.back() + A[p1++]);
            else
            {
                auto [x, y] = A[p1];
                if (x > 0)
                    S.push_back(S.back() + A[p1++]);
                else if (x < 0)
                    S.push_back(S.back() + B[p2++]);
                else
                {
                    if (y > 0)
                        S.push_back(S.back() + A[p1++]);
                    else S.push_back(S.back() + B[p2++]);
                }
            }
        }
    }
    while (p1 < n)
        S.push_back(S.back() + A[p1++]);
    while (p2 < m)
        S.push_back(S.back() + B[p2++]);
    return S;
}

LD farthest_pair(std::vector<point> pu)//最远点对
{
    pu = convex_hull(pu);
    std::vector<std::vector<point>> ppu(2);
    std::vector<point> pu1;
    for (auto x: pu)
        pu1.push_back(x * -1);
    pu1 = convex_hull(pu1);
    ppu[0] = pu, ppu[1] = pu1;
    auto ret = Minkovski(ppu);
    LD ans = 0;
    for (auto x: ret)
        ans = std::max(ans, x.len());
    return ans;
}

LD closest_pair(std::vector<point> pu)//最近点对O(nlogn)
{
    int n = pu.size();
    std::sort(pu.begin(), pu.end());
    for (int i = 1; i < n; i++)
        if (pu[i] == pu[i - 1])
            return 0;
    std::set<point, decltype([](cp u, cp v)
    { return u.y == v.y ? u.x < v.x : u.y < v.y; })> s;
    LD ans = (pu[0] - pu[1]).len2();
    for (int i = 0, j = 0; i < n; i++)
    {
        if (ans == 0)
            break;
        auto it = s.begin();
        while (!s.empty() && j < i && sqr(pu[i].x - pu[j].x) >= ans)
            s.erase(pu[j++]);
        auto oit = s.lower_bound(pu[i]);
        it = oit;
        while (ans)
        {
            if (it == s.end())
                break;
            if (sqr(it->y - pu[i].y) >= ans)
                break;
            ans = std::min(ans, (pu[i] - *it).len2());
            it++;
        }
        it = oit;
        while (ans)
        {
            if (it == s.begin())
                break;
            it--;
            if (sqr(it->y - pu[i].y) >= ans)
                break;
            ans = std::min(ans, (pu[i] - *it).len2());
        }
        s.insert(pu[i]);
    }
    return sqrtl(ans);
}

void print(std::vector<point> res)
{
    std::cout << "print:\n";
    int cnt = 0;
    for (auto [x, y]: res)
        std::cout << ++cnt << ' ' << x << ' ' << y << std::endl;
    std::cout << "end\n";
}

int onRight(cl a,cp b){return det(a.t-a.s,b-a.s)<=eps;}//如果要包含点就-eps,不要就eps
/*
 丢直线 Ax+By+C<0;
if(sgn(b)==0)
            pl.push_back(line(point(-c/a,0),point(-c/a-b,a)));
        else pl.push_back(line(point(0,-c/b),point(-b,-c/b+a)));
 * */
line get_line(LD a,LD b,LD c)//得到向量Ax+By+C<0
{
    if(sgn(b)==0)
        return line(point(-c/a,0),point(-c/a-b,a));
    else return line(point(0,-c/b),point(-b,-c/b+a));
}
std::vector<point> my_half_plane(std::vector<line> a)
{
    /*要加框取消注释 请注意对于一组解(x,y)x和y是否有要求
    a.push_back({{-INF,-INF},{INF,-INF}});
    a.push_back({{INF,-INF},{INF,INF}});
    a.push_back({{INF,INF},{-INF,INF}});
    a.push_back({{-INF,INF},{-INF,-INF}});
     */
    std::sort(a.begin(),a.end(),[&](auto x,auto y)
    {
        point u = x.t - x.s, v = y.t - y.s;
        if (u.on_up() != v.on_up())return u.on_up() < v.on_up();
//        if(sgn(det(u,v)))
        return sgn(det(u, v)) > 0;
//        else return sgn(det(x.t-y.s,y.t-y.s))<0;
    });
    int n = a.size();
    std::vector<line> que(n + 1);
    std::vector<point> p1(n + 1);
    std::vector<point> p2;
    int left = 0, right = 0;
    que[0] = a[0];
    std::vector<point>sb;
    for (int i = 1; i < n; i++)
    {
        if(sgn(det(a[i].t-a[i].s,a[i-1].t-a[i-1].s))==0)
            continue;
        while (left < right && onRight(a[i],p1[right]))right--;
        while (left < right && onRight(a[i],p1[left+1]))left++;
        que[++right] = a[i];
        if (std::abs(det(que[right].t - que[right].s, que[right - 1].t - que[right - 1].s)) <= eps)
        {
            if (onRight(que[right],que[right-1].s) &&
                dot(que[right].t-que[right].s,que[right-1].t-que[right-1].s)<=-eps)
                return sb;
            right--;
            if (!onRight(que[right],a[i].s))
                que[right] = a[i];
        }
        if (left < right)p1[right] = line_intersect(que[right], que[right - 1]);
    }
    while (left < right && onRight(que[left],p1[right]))right--;
    if (right - left <= 1)return sb;
    p1[left] = line_intersect(que[left], que[right]);
    for (int i = left; i <= right; i++)
        p2.push_back(p1[i]);
    return p2;
}
LD get_are(std::vector<point>pu)
{
    LD ans=0;
    int n=pu.size();
    for(int i=0;i<n;i++)
        ans+=det(pu[i],pu[(i+1)%n]);
    return ans/2;
}
LD get_max_inscribed_circle(const std::vector<point>pu)
{
    int n=pu.size();
    std::vector<point>dt(n);
    for(int i=0;i<n;i++)
        dt[i]=((pu[(i+1)%n]-(pu[i]+pu[(i+1)%n])/2).rot90()).unit();
    LD l=0,r=1e7;
    std::function<bool(LD)>check=[&](LD r)
    {
        std::vector<line>pl;
        for(int i=0;i<n;i++)
            pl.push_back({pu[i]+dt[i]*r,pu[(i+1)%n]+dt[i]*r});
        auto po= my_half_plane(pl);
        return !po.empty();
    };
    while(r-l>1e-4)
    {
        LD mid=(r+l)/2;
        if(check(mid))
            l=mid;
        else r=mid;
    }
    return l;
}
void my_cut_pol( std::vector<line>& lin,std::vector<std::vector<point>>& pol)//用线切凸包
{
    int cnt_line=lin.size();
    for(int i=0;i<cnt_line;i++)
    {
        int len=pol.size();
        line li=lin[i];
        for(int j=0;j<len;j++)
        {
            int len1=pol[j].size();
            for(int k=0;k<len1;k++)
            {
                LD tt1=sgn(det(li.s-pol[j][k],li.t-pol[j][k])),tt2=sgn(det(li.s-pol[j][(k+1)%len1],li.t-pol[j][(k+1)%len1]));
                if(!tt1&&!tt2)
                    break;
                if(tt1*tt2<0)
                {
                    point p1= line_intersect(li,line(pol[j][k],pol[j][(k+1)%len1])),p2;
                    std::vector<point>ne,ol;
                    ne.push_back(p1);
                    for(int t1=1;t1<len1;t1++)
                    {
                        LD tt11=det(li.s-pol[j][(k+t1)%len1],li.t-pol[j][(k+t1)%len1]);
                        LD tt12=det(li.s-pol[j][(k+t1+1)%len1],li.t-pol[j][(k+t1+1)%len1]);
                        ne.push_back(pol[j][(k+t1)%len1]);
                        if(tt11*tt12<0)
                        {
                            p2= line_intersect(li,line(pol[j][(k+t1)%len1],pol[j][(k+t1+1)%len1]));
                            ne.push_back(p2);
                            for(int t2=t1+1;t2<=len1;t2++)
                                ol.push_back(pol[j][(k+t2)%len1]);
                            break;
                        }
                        else if(tt12==0)
                        {
                            p2=pol[j][(k+t1+1)%len1];
                            ne.push_back(p2);
                            for(int t2=t1+2;t2<=len1;t2++)
                                ol.push_back(pol[j][(k+t2)%len1]);
                            break;
                        }
                    }
                    ol.push_back(p1);
                    ol.push_back(p2);
                    pol[j]=ol;
                    pol.push_back(ne);
                    break;
                }
                else if(tt2==0)
                {
                    LD tt3=sgn(det(li.s-pol[j][(k+2)%len1],li.t-pol[j][(k+2)%len1]));
                    if(tt1*tt3>=0)
                        break;
                    point p1=pol[j][(k+1)%len1],p2;
                    std::vector<point>ne,ol;
                    ne.push_back(p1);
                    for(int t1=2;t1<len1;t1++)
                    {
                        LD tt11=det(li.s-pol[j][(k+t1)%len1],li.t-pol[j][(k+t1)%len1]);
                        LD tt12=det(li.s-pol[j][(k+t1+1)%len1],li.t-pol[j][(k+t1+1)%len1]);
                        ne.push_back(pol[j][(k+t1)%len1]);
                        if(tt11*tt12<0)
                        {
                            p2= line_intersect(li,line(pol[j][(k+t1)%len1],pol[j][(k+t1+1)%len1]));
                            ne.push_back(p2);
                            for(int t2=t1+1;t2<=len1;t2++)
                                ol.push_back(pol[j][(k+t2)%len1]);
                            break;
                        }
                        else if(tt12==0)
                        {
                            p2=pol[j][(k+t1+1)%len1];
                            ne.push_back(p2);
                            for(int t2=t1+2;t2<=len1;t2++)
                                ol.push_back(pol[j][(k+t2)%len1]);
                            break;
                        }
                    }
                    ol.push_back(p1);
                    ol.push_back(p2);
                    pol[j]=ol;
                    pol.push_back(ne);
                    break;
                }
            }
        }
    }
}
std::vector<point> my_cut_to_V(const std::vector<point>&pu,cl li)
{
    int n=pu.size();
    for(int i=0;i<n;i++)
    {
        LD tt1=sgn(det(li.s-pu[i],li.t-pu[i])),tt2=sgn(det(li.s-pu[(i+1)%n],li.t-pu[(i+1)%n]));
        if(!tt1&&!tt2)
            return pu;
        if(tt1*tt2<0)
        {
            point p1= line_intersect(li,line(pu[i],pu[(i+1)%n])),p2;
            std::vector<point>ne,ol;
            ne.push_back(p1);
            for(int j=1;j<n;j++)
            {
                LD tt11=sgn(det(li.s-pu[(i+j)%n],li.t-pu[(i+j)%n])),tt12=sgn(det(li.s-pu[(i+j+1)%n],li.t-pu[(i+j+1)%n]));
                ne.push_back(pu[(i+j)%n]);
                if(tt11*tt12<0)
                {
                    p2= line_intersect(li,line(pu[(i+j)%n],pu[(i+j+1)%n]));
                    ne.push_back(p2);
                    for(int k=j+1;k<=n;k++)
                        ol.push_back(pu[(i+k)%n]);
                    break;
                }
                else if(tt12==0)
                {
                    p2=pu[(i+j+1)%n];
                    ne.push_back(p2);
                    for(int k=j+2;k<=n;k++)
                        ol.push_back(pu[(i+k)%n]);
                    break;
                }
            }
            ol.push_back(p1);
            ol.push_back(p2);
            if(tt1>0) return ol;
            else return ne;
        }
        else if(tt2==0)
        {
            LD tt3=sgn(det(li.s-pu[(i+2)%n],li.t-pu[(i+2)%n]));
            if(tt1*tt3>=0)
                return pu;
            point p1=pu[(i+1)%n],p2;
            std::vector<point>ne,ol;
            ne.push_back(p1);
            for(int j=2;j<n;j++)
            {
                LD tt11=sgn(det(li.s-pu[(i+j)%n],li.t-pu[(i+j)%n]));
                LD tt12=sgn(det(li.s-pu[(i+j+1)%n],li.t-pu[(i+j+1)%n]));
                ne.push_back(pu[(i+j)%n]);
                if(tt11*tt12<0)
                {
                    p2= line_intersect(li,line(pu[(i+j)%n],pu[(i+j+1)%n]));
                    ne.push_back(p2);
                    for(int k=j+1;k<=n;k++)
                        ol.push_back(pu[(i+k)%n]);
                    break;

                }
                else if(tt12==0)
                {
                    p2=pu[(i+j+1)%n];
                    ne.push_back(p2);
                    for(int k=j+2;k<=n;k++)
                        ol.push_back(pu[(i+k)%n]);
                    break;
                }
            }
            ol.push_back(p1);
            ol.push_back(p2);
            if(tt1>0)return ol;
            else return ne;
        }
    }
    return pu;
}
std::vector<std::vector<point>> Vtu(const std::vector<point>pu)
{
    int n=pu.size();
    std::vector<int>id(n);
    for(int i=0;i<n;i++)
        id[i]=i;
    std::shuffle(id.begin(),id.end(),rnd);
    std::vector<point>base;
    LD inf=1e6+10;
    base.push_back(point(-inf,-inf));
    base.push_back(point(inf,-inf));
    base.push_back(point(inf,inf));
    base.push_back(point(-inf,inf));
    std::vector<std::vector<point>>ret(n);
    for(int i=0;i<n;i++)
    {
        std::vector<point>p1(base);
        for(int j=0;j<n;j++)
        {
            if(i!=id[j])
            {
                point mid=(pu[i]+pu[id[j]])/2;
                p1= my_cut_to_V(p1,line(mid,mid+(pu[id[j]]-mid).rot90()));
            }
        }
        ret[i]=p1;
    }
    return ret;
}
std::vector<point> my_get_line_cut_pol(cl li,const std::vector<point>&pu)//用直线切简单多边型得到的点,简单多边形要逆时针,无180°角。
{
    point p1=li.s, p2=li.t;
    std::vector<point> np;
    LD ans = 0;
    int n=pu.size();
    for (int i = 0; i < n; i++)
    {
        if (two_side(pu[i],pu[(i+1)%n],line(p1,p2)))
        {
            np.push_back(line_intersect(line(pu[i], pu[(i + 1) % n]), line(p1, p2)));
            continue;
        }
        int tt1 = sgn(det(p1 - pu[i], p2 - pu[i])), tt2 = sgn(
                det(p1 - pu[(i + 1) % n], p2 - pu[(i + 1) % n])), tt3 = sgn(
                det(p1 - pu[(i + 2) % n], p2 - pu[(i + 2) % n]));
        if (tt2 == 0)
        {
            if (tt1 * tt3 > 0)
                continue;
            else if (tt1 * tt3 < 0)
                np.push_back(pu[(i + 1) % n]);
            else if (sgn(det(pu[(i + 2) % n] - pu[(i + 1) % n], pu[i] - pu[(i + 1) % n])) > 0)
                np.push_back(pu[(i + 1) % n]);
        }
    }
    std::sort(np.begin(), np.end(), [&](auto u, auto v)
    {
        if (p1.x == p2.x)
            return u.y < v.y;
        else
            return u.x < v.x;
    });
    return np;
}
bool line_in_polygon(cl li,const std::vector<point>&p)//
{
    cp u=li.s,v=li.t;
//    if(!in_polygon(u,p)||!in_polygon(v,p))//默认两个点已经在多边形内了
//        return 0;
    if(u==v)
        return true;
    int n=p.size();
    for(int i=0;i<n;i++)
    {
        int j=(i+1)%n,k=(i+2)%n;
        cp ii=p[i],jj=p[j],kk=p[k];
        if(intersect_judge_strict(line(u,v),line(ii,jj)))return 0;
        if(point_on_segment(jj,line(u,v)))
        {
            bool good=true,left= turn_left(ii,jj,kk);
            for(auto x:{u,v})
            {
                if(left)
                    good&= turn_left(ii,jj,x)&& turn_left(jj,kk,x);
                else good&=!(turn_left_strict(jj,x,kk)&& turn_left_strict(jj,ii,x));
            }
            if(!good)return 0;
        }
    }
    return 1;
}//判断线段是否在简单多边形内
void solve()
{
    int n,m;
    std::cin>>n>>m;
    std::vector<point>opu(n),pu1(m);
    std::vector<std::vector<point>>PU(n);
    std::vector<std::pair<point,int>>pu;
    for(int i=0;i<n;i++)
        opu[i].read();
    for(int i=0;i<m;i++)
    {
        pu1[i].read();
        for(int j=0;j<n;j++)
            if(point_on_segment(pu1[i],line(opu[j],opu[(j+1)%n])))
            {
                PU[j].push_back(pu1[i]);
                break;
            }
    }
    for(int j=0;j<n;j++)
        std::sort(PU[j].begin(),PU[j].end(),[&](auto u,auto v){
            return sgn(dot(v-u,opu[(j+1)%n]-opu[j]))>0;
        });
    for(int i=0;i<n;i++)
    {
        pu.push_back(std::make_pair(opu[i],0));
        for(auto p:PU[i])
            pu.push_back(std::make_pair(p,1));
    }
    int len=pu.size();
    std::vector<std::vector<LD>>dp(len,std::vector<LD>(len));
//    for(int i=0;i<len;i++)
//        pu[i].first.print();
    for(int i=0;i<len;i++)
    {
        for (int j = 0; j < len; j++)
            if (line_in_polygon(line(pu[i].first, pu[j].first), opu))
                dp[i][j] = dis(pu[i].first, pu[j].first);
            else dp[i][j] = 1e18;
    }
    for(int k=0;k<len;k++)
    {
        for(int x=0;x<len;x++)
            for(int y=0;y<len;y++)
                dp[x][y]=std::min(dp[x][y],dp[x][k]+dp[k][y]);
    }
    int flag=-1,be;
    LD ans=0;
    for(int i=0;i<len;i++)
    {
        if(pu[i].second==1)
        {
            if(flag==-1)
                be=flag=i;
            else
            {
                ans+=dp[flag][i];
                flag=i;
            }
        }
    }
    ans+=dp[flag][be];
    std::cout<<ans<<std::endl;

}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0), std::cout.tie(0);
    std::cout << std::fixed << std::setprecision(10);
    int T = 1;

//    std::cin>>T;
    for (int i = 1; i <= T; i++)
        solve();
}

详细

Test #1:

score: 100
Accepted
time: 1ms
memory: 3940kb

input:

4 4
0 0
2 0
2 2
0 2
1 0
1 2
2 1
0 1

output:

5.6568542495

result:

ok found '5.6568542', expected '5.6568542', error '0.0000000'

Test #2:

score: 0
Accepted
time: 1ms
memory: 4084kb

input:

8 2
0 0
4 0
4 4
0 4
0 3
3 3
3 1
0 1
0 0
0 4

output:

16.6491106407

result:

ok found '16.6491106', expected '16.6491106', error '0.0000000'

Test #3:

score: 0
Accepted
time: 1ms
memory: 3948kb

input:

4 4
0 0
2 0
2 2
0 2
1 0
2 1
1 2
0 1

output:

5.6568542495

result:

ok found '5.6568542', expected '5.6568542', error '0.0000000'

Test #4:

score: 0
Accepted
time: 0ms
memory: 3952kb

input:

8 2
0 0
4 0
4 4
0 4
0 3
3 3
3 1
0 1
0 0
0 4

output:

16.6491106407

result:

ok found '16.6491106', expected '16.6491106', error '0.0000000'

Test #5:

score: -100
Wrong Answer
time: 42ms
memory: 4248kb

input:

76 98
268 97
299 202
133 205
110 251
384 226
332 198
532 241
448 83
268 82
543 62
873 93
387 317
905 90
945 132
827 335
983 222
919 534
945 264
910 287
789 705
837 176
793 563
777 665
782 345
746 315
715 315
810 161
369 599
278 671
641 423
703 344
753 619
672 402
596 709
161 701
216 857
325 942
135 ...

output:

13621.6013842407

result:

wrong answer 1st numbers differ - expected: '14645.5751139', found: '13621.6013842', error = '0.0699169'