• 【题解】Mogohu-Rea Idol [CF87E]


    【题解】Mogohu-Rea Idol [CF87E]

    传送门:( ext{Mogohu-Rea Idol}) ( ext{[CF87E]})

    【题目描述】

    按逆时针顺序给出三个凸包点集 (A,B,C),每次查询给出点 (q),问是否存在点 (ain A,bin B,cin C) 满足 (q)(Delta abc) 的重心。

    【分析】

    【学习笔记】计算几何全家桶

    目前我所知的第三道闵可夫斯基和的题(貌似是个冷门老题)

    考虑三角形重心 (Q) 的基本性质:(vec{OA}+vec{OB}+vec{OC}=3vec{OQ})

    然后就是个板子题了...

    对三个凸包求个和,得到 (P={a+b+c|ain A,bin B,cin C}),然后直接判断点 (q*3) 是否在 (P) 以内即可。

    注意题目给出的虽然是严格凸包,但还是要自己写个算法跑一下,目的是将坐标最小的放在第一个位置,否则后面对凸包求和时会出问题(也可以直接枚举找最小点作为凸包起点)。

    然后就是做完闵可夫斯基和后要再对其求一下凸包,目的是去掉平行边(或者说重边。在 (P) 上表现为三点共线)。

    时间复杂度:(O((n+m)log n))

    其实可以把两部分求凸包的过程都换掉:前面枚举找最小点、多加一个特判处理重边,就变成了 (O(n+mlog n)),但意义不大。

    【Code】

    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define LD double
    #define LL long long
    #define Vector Point
    #define Re register int
    using namespace std;
    const int N=5e4+3;
    const LD eps=1e-8,Pi=acos(-1.0);
    inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    struct Point{
        LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
        inline void In(){Re X,Y;in(X),in(Y),x=X,y=Y;}
        inline bool operator<(const Point &O)const{return dcmp(x-O.x)?x<O.x:y<O.y;}
    };
    inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
    inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
    inline Vector operator+(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
    inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    inline Vector operator*(Vector a,LD b){return Vector(a.x*b,a.y*b);}
    inline int pan_PL(Point p,Point a,Point b){//【判断点P是否在直线AB上】
        return !dcmp(Cro(p-a,p-b))&&dcmp(Dot(p-a,p-b))<0;
    }
    inline bool cmp1(Vector a,Vector b){return a.x==b.x?a.y<b.y:a.x<b.x;};//按坐标排序
    inline int ConvexHull(Point *P,Re n,Point *cp){//【Graham扫描法】求凸包
        sort(P+1,P+n+1,cmp1);
        Re t=0;
        for(Re i=1;i<=n;++i){//下凸包
            while(t>1&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
            cp[++t]=P[i];
        }
        Re St=t;
        for(Re i=n-1;i>=1;--i){//上凸包
            while(t>St&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
            cp[++t]=P[i];
        }
        return --t;//要减一
    }
    inline int PIP(Point *P,Re n,Point a){//【二分法】判断点A是否在凸多边形Poly以内
        //点按逆时针给出
        if(dcmp(Cro(a-P[1],P[2]-P[1]))>0||dcmp(Cro(P[n]-P[1],a-P[1]))>0)return 0;//在P[1_2]或P[1_n]外
        if(pan_PL(a,P[1],P[2])||pan_PL(a,P[1],P[n]))return 1;//在P[1_2]或P[1_n]上
        Re l=2,r=n-1;
        while(l<r){//二分找到一个位置pos使得P[1]_A在P[1_pos],P[1_(pos+1)]之间
            Re mid=l+r+1>>1;
            if(dcmp(Cro(a-P[1],P[mid]-P[1]))>0)r=mid-1;
            else l=mid;
        }
        return dcmp(Cro(a-P[r],P[r+1]-P[r]))<=0;
    }
    Vector V1[N*3],V2[N*3];
    inline int Mincowski(Point *P1,Re n,Point *P2,Re m,Point *P){//【闵可夫斯基和】求两个凸包{P1},{P2}的向量集合{V}={P1+P2}构成的凸包
        for(Re i=1;i<=n;++i)V1[i]=P1[i<n?i+1:1]-P1[i];
        for(Re i=1;i<=m;++i)V2[i]=P2[i<m?i+1:1]-P2[i];
        Re t=0,i=1,j=1;P[++t]=P1[1]+P2[1];
        while(i<=n&&j<=m)++t,P[t]=P[t-1]+(dcmp(Cro(V1[i],V2[j]))>0?V1[i++]:V2[j++]);
        while(i<=n)++t,P[t]=P[t-1]+V1[i++];
        while(j<=m)++t,P[t]=P[t-1]+V2[j++];
        return t;
    }
    int n,T,n1,n2,n3;Point Q,P[N*3],cp[N*3],P1[N],P2[N],P3[N];
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n1);for(Re i=1;i<=n1;++i)P1[i].In();n1=ConvexHull(P1,n1,cp);for(Re i=1;i<=n1;++i)P1[i]=cp[i];
        in(n2);for(Re i=1;i<=n2;++i)P2[i].In();n2=ConvexHull(P2,n2,cp);for(Re i=1;i<=n2;++i)P2[i]=cp[i];
        in(n3);for(Re i=1;i<=n3;++i)P3[i].In();n3=ConvexHull(P3,n3,cp);for(Re i=1;i<=n3;++i)P3[i]=cp[i];
        n=Mincowski(P1,n1,P2,n2,P),n=Mincowski(P,n,P3,n3,cp),n=ConvexHull(cp,n,P),in(T);//这里对P求一次凸包或者分开求两次凸包效果都是一样的
    //    n=Mincowski(P1,n1,P2,n2,cp),n=ConvexHull(cp,n,P);
    //    n=Mincowski(P,n,P3,n3,cp),n=ConvexHull(cp,n,P),in(T);
        while(T--)Q.In(),puts(PIP(P,n,Q*3.0)?"YES":"NO");
    }
    
  • 相关阅读:
    解决VUE刷新或者加载出现闪烁
    解决VUE<router-link>不能触发点击事件
    H5的本地存储web Storage
    格式化数字格式
    移动终端浏览器版本信息
    新的开始
    PHP用PHPExcel导入Excel表格的数据到MySQL(thinkPHP3.2.3)
    Layui的分页模块在网站中的应用
    PHPstorm连接ftp
    自定义PHPstorm快捷键
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/13027432.html
Copyright © 2020-2023  润新知