zoukankan      html  css  js  c++  java
  • [CF166B] Polygons

    Description

    给定两个凸多边形 (A,B),询问 (B) 是否严格在 (A) 内。

    Solution

    (A,B) 的所有点构造非严格凸包,如果这个凸包等于 (B),则符合条件。

    (方法真的挺妙的)

    #include <bits/stdc++.h>
    using namespace std;
    #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;
            scanf("%lf%lf", &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, point p2)
        {
            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));
    }
    db area(vector<point> A)
    {
        db ans = 0;
        for (int i = 0; i < A.size(); i++) ans += cross(A[i], A[(i + 1) % A.size()]);
        return ans / 2;
    }
    int checkconvex(vector<point>A)
    {
        int n = A.size();
        A.push_back(A[0]);
        A.push_back(A[1]);
        for (int i = 0; i < n; i++) if (sign(cross(A[i + 1] - A[i], A[i + 2] - A[i])) == -1) return 0;
        return 1;
    }
    int contain(vector<point>A, point q)
    {
        int pd = 0;
        A.push_back(A[0]);
        for (int i = 1; i < A.size(); i++)
        {
            point u = A[i - 1], v = A[i];
            if (onS(u, v, q)) return 1;
            if (cmp(u.y, v.y) > 0) swap(u, v);
            if (cmp(u.y, q.y) >= 0 || cmp(v.y, q.y) < 0) continue;
            if (sign(cross(u - v, q - v)) < 0) pd ^= 1;
        }
        return pd << 1;
    }
    vector<point> ConvexHull(vector<point>A, int flag = 1)
    {
        int n = A.size();
        vector<point>ans(n * 2);
        sort(A.begin(), A.end());
        int now = -1;
        for (int i = 0; i < A.size(); i++)
        {
            while (now > 0 && sign(cross(ans[now] - ans[now - 1], A[i] - ans[now - 1])) < flag) now--;
            ans[++now] = A[i];
        }
        int pre = now;
        for (int i = n - 2; i >= 0; i--)
        {
            while (now > pre && sign(cross(ans[now] - ans[now - 1], A[i] - ans[now - 1])) < flag) now--;
            ans[++now] = A[i];
        }
        ans.resize(now);
        return ans;
    }
    db convexDiameter(vector<point>A)
    {
        int now = 0, n = A.size();
        db ans = 0;
        for (int i = 0; i < A.size(); i++)
        {
            now = max(now, i);
            while (1)
            {
                db p1 = A[i].dis(A[now % n]), p2 = A[i].dis(A[(now + 1) % n]);
                ans = max(ans, max(p1, p2));
                if (p2 > p1) now++;
                else break;
            }
        }
        return ans;
    }
    vector<point> convexcut(vector<point>A, point p1, point p2)
    {
        int n = A.size();
        A.push_back(A[0]);
        vector<point>ans;
        for (int i = 0; i < n; i++)
        {
            int w1 = clockwise(p1, p2, A[i]), w2 = clockwise(p1, p2, A[i + 1]);
            if (w1 >= 0) ans.push_back(A[i]);
            if (w1 * w2 < 0) ans.push_back(getLL(p1, p2, A[i], A[i + 1]));
        }
        return ans;
    }
    int checkPoS(vector<point>A, point p1, point p2)
    {
        // 多边形 A 和直线 ( 线段 )p1->p2 严格相交 , 注释部分为线段
        struct ins
        {
            point m, u, v;
            int operator < (const ins& k) const
            {
                return m < k.m;
            }
        };
        vector<ins>B;
        //if (contain(A,p1)==2||contain(A,p2)==2) return 1;
        vector<point>poly = A;
        A.push_back(A[0]);
        for (int i = 1; i < A.size(); i++) if (checkLL(A[i - 1], A[i], p1, p2))
            {
                point m = getLL(A[i - 1], A[i], p1, p2);
                if (inmid(A[i - 1], A[i], m)/*&&inmid(p1,p2,m)*/) B.push_back((ins)
                {
                    m, A[i - 1], A[i]
                });
            }
        if (B.size() == 0) return 0;
        sort(B.begin(), B.end());
        int now = 1;
        while (now < B.size() && B[now].m == B[0].m) now++;
        if (now == B.size()) return 0;
        int flag = contain(poly, (B[0].m + B[now].m) / 2);
        if (flag == 2) return 1;
        point d = B[now].m - B[0].m;
        for (int i = now; i < B.size(); i++)
        {
            if (!(B[i].m == B[i - 1].m) && flag == 2) return 1;
            int tag = sign(cross(B[i].v - B[i].u, B[i].m + d - B[i].u));
            if (B[i].m == B[i].u || B[i].m == B[i].v) flag += tag;
            else flag += tag * 2;
        }
        //return 0;
        return flag == 2;
    }
    int checkinp(point r, point l, point m)
    {
        if (compareangle(l, r))
        {
            return compareangle(l, m) && compareangle(m, r);
        }
        return compareangle(l, m) || compareangle(m, r);
    
    }
    int checkPosFast(vector<point>A, point p1, point p2)   // 快速检查线段是否和多边形严格相交
    {
        if (contain(A, p1) == 2 || contain(A, p2) == 2) return 1;
        if (p1 == p2) return 0;
        A.push_back(A[0]);
        A.push_back(A[1]);
        for (int i = 1; i + 1 < A.size(); i++)
            if (checkLL(A[i - 1], A[i], p1, p2))
            {
                point now = getLL(A[i - 1], A[i], p1, p2);
                if (inmid(A[i - 1], A[i], now) == 0 || inmid(p1, p2, now) == 0) continue;
                if (now == A[i])
                {
                    if (A[i] == p2) continue;
                    point pre = A[i - 1], ne = A[i + 1];
                    if (checkinp(pre - now, ne - now, p2 - now)) return 1;
                }
                else if (now == p1)
                {
                    if (p1 == A[i - 1] || p1 == A[i]) continue;
                    if (checkinp(A[i - 1] - p1, A[i] - p1, p2 - p1)) return 1;
                }
                else if (now == p2 || now == A[i - 1]) continue;
                else return 1;
            }
        return 0;
    }
    // 拆分凸包成上下凸壳 凸包尽量都随机旋转一个角度来避免出现相同横坐标
    // 尽量特判只有一个点的情况 凸包逆时针
    void getUDP(vector<point>A, vector<point>& U, vector<point>& D)
    {
        db l = 1e100, r = -1e100;
        for (int i = 0; i < A.size(); i++) l = min(l, A[i].x), r = max(r, A[i].x);
        int wherel, wherer;
        for (int i = 0; i < A.size(); i++) if (cmp(A[i].x, l) == 0) wherel = i;
        for (int i = A.size(); i; i--) if (cmp(A[i - 1].x, r) == 0) wherer = i - 1;
        U.clear();
        D.clear();
        int now = wherel;
        while (1)
        {
            D.push_back(A[now]);
            if (now == wherer) break;
            now++;
            if (now >= A.size()) now = 0;
        }
        now = wherel;
        while (1)
        {
            U.push_back(A[now]);
            if (now == wherer) break;
            now--;
            if (now < 0) now = A.size() - 1;
        }
    }
    // 需要保证凸包点数大于等于 3,2 内部 ,1 边界 ,0 外部
    int containCoP(const vector<point>& U, const vector<point>& D, point k)
    {
        db lx = U[0].x, rx = U[U.size() - 1].x;
        if (k == U[0] || k == U[U.size() - 1]) return 1;
        if (cmp(k.x, lx) == -1 || cmp(k.x, rx) == 1) return 0;
        int where1 = lower_bound(U.begin(), U.end(), (point)
        {
            k.x, -1e100
        }) - U.begin();
        int where2 = lower_bound(D.begin(), D.end(), (point)
        {
            k.x, -1e100
        }) - D.begin();
        int w1 = clockwise(U[where1 - 1], U[where1], k), w2 = clockwise(D[where2 - 1], D[where2], k);
        if (w1 == 1 || w2 == -1) return 0;
        else if (w1 == 0 || w2 == 0) return 1;
        return 2;
    }
    // d 是方向 , 输出上方切点和下方切点
    pair<point, point> getTangentCow(const vector<point>& U, const vector<point>& D, point d)
    {
        if (sign(d.x) < 0 || (sign(d.x) == 0 && sign(d.y) < 0)) d = d * (-1);
        point whereU, whereD;
        if (sign(d.x) == 0) return mp(U[0], U[U.size() - 1]);
        int l = 0, r = U.size() - 1, ans = 0;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (sign(cross(U[mid + 1] - U[mid], d)) <= 0) l = mid + 1, ans = mid + 1;
            else r = mid;
        }
        whereU = U[ans];
        l = 0, r = D.size() - 1, ans = 0;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (sign(cross(D[mid + 1] - D[mid], d)) >= 0) l = mid + 1, ans = mid + 1;
            else r = mid;
        }
        whereD = D[ans];
        return mp(whereU, whereD);
    }
    // 先检查 contain, 逆时针给出
    pair<point, point> getTangentCoP(const vector<point>& U, const vector<point>& D, point k)
    {
        db lx = U[0].x, rx = U[U.size() - 1].x;
        if (k.x < lx)
        {
            int l = 0, r = U.size() - 1, ans = U.size() - 1;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (clockwise(k, U[mid], U[mid + 1]) == 1) l = mid + 1;
                else ans = mid, r = mid;
            }
            point w1 = U[ans];
            l = 0, r = D.size() - 1, ans = D.size() - 1;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (clockwise(k, D[mid], D[mid + 1]) == -1) l = mid + 1;
                else ans = mid, r = mid;
            }
            point w2 = D[ans];
            return mp(w1, w2);
        }
        else if (k.x > rx)
        {
            int l = 1, r = U.size(), ans = 0;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (clockwise(k, U[mid], U[mid - 1]) == -1) r = mid;
                else ans = mid, l = mid + 1;
            }
            point w1 = U[ans];
            l = 1, r = D.size(), ans = 0;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (clockwise(k, D[mid], D[mid - 1]) == 1) r = mid;
                else ans = mid, l = mid + 1;
            }
            point w2 = D[ans];
            return mp(w2, w1);
        }
        else
        {
            int where1 = lower_bound(U.begin(), U.end(), (point)
            {
                k.x, -1e100
            }) - U.begin();
            int where2 = lower_bound(D.begin(), D.end(), (point)
            {
                k.x, -1e100
            }) - D.begin();
            if ((k.x == lx && k.y > U[0].y) || (where1 && clockwise(U[where1 - 1], U[where1], k) == 1))
            {
                int l = 1, r = where1 + 1, ans = 0;
                while (l < r)
                {
                    int mid = l + r >> 1;
                    if (clockwise(k, U[mid], U[mid - 1]) == 1) ans = mid, l = mid + 1;
                    else r = mid;
                }
                point w1 = U[ans];
                l = where1, r = U.size() - 1, ans = U.size() - 1;
                while (l < r)
                {
                    int mid = l + r >> 1;
                    if (clockwise(k, U[mid], U[mid + 1]) == 1) l = mid + 1;
                    else ans = mid, r = mid;
                }
                point w2 = U[ans];
                return mp(w2, w1);
            }
            else
            {
                int l = 1, r = where2 + 1, ans = 0;
                while (l < r)
                {
                    int mid = l + r >> 1;
                    if (clockwise(k, D[mid], D[mid - 1]) == -1) ans = mid, l = mid + 1;
                    else r = mid;
                }
                point w1 = D[ans];
                l = where2, r = D.size() - 1, ans = D.size() - 1;
                while (l < r)
                {
                    int mid = l + r >> 1;
                    if (clockwise(k, D[mid], D[mid + 1]) == -1) l = mid + 1;
                    else ans = mid, r = mid;
                }
                point w2 = D[ans];
                return mp(w1, w2);
            }
        }
    }
    
    signed main()
    {
        int n,m;
        cin>>n;
        vector<point> a,b,c;
        for(int i=1;i<=n;i++)
        {
            point tmp;
            tmp.scan();
            a.push_back(tmp);
            c.push_back(tmp);
        }
        cin>>m;
        for(int i=1;i<=m;i++)
        {
            point tmp;
            tmp.scan();
            b.push_back(tmp);
            c.push_back(tmp);
        }
        c=ConvexHull(c,0);
        sort(a.begin(),a.end());
        sort(c.begin(),c.end());
        int flag=1;
        if(a.size()!=c.size())
        {
            flag=0;
        }
        else
        {
            for(int i=0;i<a.size();i++)
            {
                if(!(a[i]==c[i]))
                {
                    flag=0;
                    break;
                }
            }
        }
        if(flag) puts("YES");
        else puts("NO");
    }
    
    
  • 相关阅读:
    Java多个版本共存
    在RestHighLevelClient中增加用户名密码验证
    request Body 查询
    threadLocal
    thread 中断 interrupt
    Thread 状态和创建方法
    URI Search
    解析器
    基本crud
    第4章 SQL与关系数据库基本操作
  • 原文地址:https://www.cnblogs.com/mollnn/p/13617944.html
Copyright © 2011-2022 走看看