zoukankan      html  css  js  c++  java
  • P4557 [JSOI2018]战争

    给出两个凸包。之后有q个询问问你第一个凸包加上给出的向量会不会与第二个凸包有交点。

    这里假设A为第一个凸包的点集,B为第二个凸包的点击,p为移动的向量。

    那么由题意可以得到: A + p = B, 将式子稍微变形可以得到这个移动向量的范围,即p = B - A

    参考链接:https://www.cnblogs.com/xzyxzy/p/10229921.html

    这里引入一个几何概念:

    闵可夫斯基和:定义F(A, B)为闵可夫斯基和

    F(A, B) = {(ai+bi, aj+bj)| Vai属于A, Vbi属于B}

    通俗一点:就是将一个多边形的一个点定到另一个多边形上,之后定点绕着多边形移动所画出的区域就是。

    图片来源于:上面的博客。

    这里还需要一个二分判断点是否在凸包内的。

    具体的思想就是叉积,两条线的叉积能确定线的相对位置,所以可以二分。

    以下是代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10;
    typedef long long ll;
    
    struct Point {
        ll x, y;
        Point(){x=y=0;}
        Point(ll _x, ll _y):x(_x),y(_y){}
        Point operator-(const Point& _p) const{return Point(x-_p.x, y-_p.y);}
        Point operator+(const Point& _p) const{return Point(x+_p.x, y+_p.y);}
    
        ll operator*(const Point& _p) const{return x * _p.x + y * _p.y;}
        ll operator^(const Point& _p) const{return x*_p.y - y*_p.x;}
    
        void input(){scanf("%lld%lld", &x, &y);}
        /*sort*/
        bool operator==(const Point& _p) const{return x==_p.x&&y==_p.y;}
        bool operator<(const Point& _p) const{return x==_p.x ? y<_p.y : x<_p.x;}
    
    } A[N], B[N], C[N];
    
    ll cro(Point a, Point b, Point c) {return (b-a) ^ (c-a);}
    ll dot(Point a, Point b, Point c) {return (b-a) * (c-a);}
    
    int ConvexHull(Point *p, int n, Point* ch, int flag=1) {
        sort(p, p+n);      //先比较x坐标,再比较y坐标
        if (flag) n = unique(p, p+n)-p;
        int m = 0;
        for (int i = 0; i < n; ++ i) {
            while (m > 1 && cro(ch[m-2], ch[m-1], p[i]) < flag) -- m;
            ch[m++] = p[i];
        }
        int temp = m;
        for (int i = n - 2; i >= 0; -- i) {
            while (m > temp && cro(ch[m-2], ch[m-1], p[i]) < flag) -- m;
            ch[m++] = p[i];
        }
        return m -= (n > 1);
    }
    
    //点在线段上(包含端点),在为 1 ,不在为 0
    bool isPointOnSegment(Point P,Point A,Point B) {
        return cro(P, A, B) == 0 && dot(P, A, B) <= 0;  // 不包含端点时为 <0
    }
    //判断点在凸包内模板 O(logn)
    //凸包为逆时针
    //在边界,返回0,在内部,返回1,在外部,返回-1
    int check(Point A, Point*p, int n ) {
        if (isPointOnSegment(A, p[0], p[1])) return 0; // 包含端点
        if (isPointOnSegment(A, p[0], p[n-1])) return 0;
        int l = 1, r = n - 2, mid;
        while (l <= r) {
            mid = l + r >> 1;
            ll a1 = cro(p[0], p[mid], A);
            ll a2 = cro(p[0], p[mid+1], A);
            if (a1 >= 0 && a2 <= 0) {
                ll tmp = cro(p[mid], p[mid+1], A);
                if (tmp > 0)return 1;
                if (tmp == 0) return 0;
                return -1;
            }
            else if (a1 < 0) r = mid - 1;
            else l = mid + 1;
        }
        return -1;
    }
    
    int Minkowski(Point *A, int n, Point *B, int m, Point *C){
        int t = 0, x = 1, y = 1;
        C[t++] = A[0] + B[0];
        A[n] = A[0], B[m] = B[0];
        while (x <= n && y <= m)
            if ( ((A[x]-A[x-1]) ^ (B[y]-B[y-1])) > 0)
                C[t] = C[t-1] + A[x] - A[x-1], t ++, x ++;
            else
                C[t] = C[t-1] + B[y] - B[y-1], t ++, y ++;
        while (x <= n) C[t] = C[t-1] + A[x] - A[x-1], t ++, x ++;
        while (y <= m) C[t] = C[t-1] + B[y] - B[y-1], t ++, y ++;
        return t - 1;
    }
    
    int main() {
    //    freopen("in.txt", "r", stdin);
    //    freopen("out.txt", "w", stdout);
        int n, m, q;
        scanf("%d%d%d", &n, &m, &q);
        for (int i = 0; i < n; ++ i) A[i].input();
        for (int i = 0; i < m; ++ i)
            B[i].input(), B[i].x *= -1, B[i].y *= -1;
        n = ConvexHull(A, n, C);
        memcpy(A, C,sizeof(Point)*(n));
        m = ConvexHull(B, m, C);
        memcpy(B, C,sizeof(Point)*(m));
    
        int p = Minkowski(A, n, B, m, C);
    
        for (int i = 0; i < q; ++ i) {
            Point temp; temp.input();
            puts(check(temp, C, p) == -1 ? "0" : "1");
        }
    
        return 0;
    }
    View Code

     这里有个小知识: 闵可夫斯基和凸包上的点等于向量种类数

  • 相关阅读:
    shell的一本书
    linux设置网络三种方法
    BIOS讲解
    对于ssh和hadoop联系讲解和ssh的基本内容
    Httphandler
    ASP.NET配置文件
    Httpmoudle
    ASP.NET页面生命周期
    ASP.NET页面跳转方法的集合
    OutputCache的使用
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/14506477.html
Copyright © 2011-2022 走看看