zoukankan      html  css  js  c++  java
  • LightOj1190

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1190

    题意:给你一个多边形含有n个点;然后又m个查询,每次判断点(x, y)是否在多边形的内部;

    射线法判断即可适用于任何(凸或凹)多边形;时间复杂度为O(n);

    判断一个点是在多边形内部,边上还是在外部,时间复杂度为O(n);射线法可以正确用于凹多边形;

    射线法是使用最广泛的算法,这是由于相比较其他算法而言,它不但可以正确使用在凹多边形上,而且不需要考虑精度误差问题。该算法思想是从点出发向右水平做

    一条射线,计算该射线与多边形的边的相交点个数,当点不在多边形边上时,如果是奇数,那么点就一定在多边形内部,否则,在外部。

    /*
    射线法:判断一个点是在多边形内部,边上还是在外部,时间复杂度为O(n);
    射线法可以正确用于凹多边形;
    射线法是使用最广泛的算法,这是由于相比较其他算法而言,它不但可以正
    确使用在凹多边形上,而且不需要考虑精度误差问题。该算法思想是从点出
    发向右水平做一条射线,计算该射线与多边形的边的相交点个数,当点不在
    多边形边上时,如果是奇数,那么点就一定在多边形内部,否则,在外部。
    */
    #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int N = 2010;
    const double eps = 1e-10;
    const int INF = 0x3f3f3f3f;
    //////////////////////////////////////////////////////////////////
    struct point
    {
        double x, y;
        point(double x=0, double y=0) : x(x), y(y){}
        friend point operator - (const point& p1, const point& p2)
        {
            return point(p1.x-p2.x, p1.y-p2.y);
        }
        friend double operator ^ (const point& p1, const point& p2)
        {
            return p1.x*p2.y - p1.y*p2.x;
        }
    };
    //////////////////////////////////////////////////////////////////
    struct Segment
    {
        point s, e;
    };
    //////////////////////////////////////////////////////////////////
    ///判断一个double类型的数是  0  <0  >0;
    int Sign(double x)
    {
        if( fabs(x) < eps )return 0;
        if(x > 0)return 1;
        return -1;
    }
    //////////////////////////////////////////////////////////////////
    ///判断o在ab的哪边;0:o在直线ab上; >0:在左边; <0:在右边;
    double cross(point o, point a, point b)
    {
        return ((a-o)^(b-o));
    }
    //////////////////////////////////////////////////////////////////
    ///已知abc三点在一条直线上,判断点a是否在线段bc之间;<=0:在   >0:不在;
    int Between(point a, point b, point c)
    {
        if(fabs(b.x-c.x) > fabs(b.y-c.y))
            return Sign(min(b.x, c.x)-a.x)*Sign(max(b.x, c.x)-a.x);
        else
            return Sign(min(b.y, c.y)-a.y)*Sign(max(b.y, c.y)-a.y);
    }
    //////////////////////////////////////////////////////////////////
    ///判断点p0和线段S上,<=0:在,1:不在;
    int PointOnSegment(point p0, Segment S)
    {
        if(Sign(cross(S.s, S.e, p0)) == 0)
            return Between(p0, S.s, S.e);
        return 1;
    }
    //////////////////////////////////////////////////////////////////
    ///求线段a和线段b的交点个数;
    int SegmentCross(Segment a, Segment b)
    {
        double x1 = cross(a.s, a.e, b.s);
        double x2 = cross(a.s, a.e, b.e);
        double x3 = cross(b.s, b.e, a.s);
        double x4 = cross(b.s, b.e, a.e);
    
        if(Sign(x1*x2)<0 && Sign(x3*x4)<0) return 1;
        if((Sign(x1)==0 && Between(b.s, a.s, a.e)<=0) ||
           (Sign(x2)==0 && Between(b.e, a.s, a.e)<=0) ||
           (Sign(x3)==0 && Between(a.s, b.s, b.e)<=0) ||
           (Sign(x4)==0 && Between(a.e, b.s, b.e)<=0))
           return 2;
        return 0;
    }
    //////////////////////////////////////////////////////////////////
    ///判断点p0与含有n个节点的多边形的位置关系,p数组是顶点集合;
    ///返回0:边上或顶点上,    1:外面,   -1:里面;
    int PointInPolygon(point p0, point p[], int n)
    {
        Segment L, S;
        point temp;
        L.s = p0, L.e = point(INF, p0.y);///以p0为起点的射线L;
    
        int counts = 0;
        p[n] = p[0];
    
        for(int i=1; i<=n; i++)
        {
            S.s = p[i-1], S.e = p[i];
    
            if(PointOnSegment(p0, S) <= 0) return 0;
            if(S.s.y == S.e.y) continue;///和射线平行;
    
            if(S.s.y > S.e.y) temp = S.s;
            else temp = S.e;
    
            if(PointOnSegment(temp, L) == -1)
                counts ++;
            else if(SegmentCross(L, S) == 1)
                counts ++;
        }
        if(counts%2) return -1;
        return 1;
    }
    //////////////////////////////////////////////////////////////////
    int main()
    {
        point p[N];
        int T, tCase = 1, n, q;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%d", &n);
            for(int i=0; i<n; i++)
                scanf("%lf %lf", &p[i].x, &p[i].y);
            scanf("%d", &q);
            printf("Case %d:
    ", tCase++);
            for(int i=1; i<=q; i++)
            {
                int x, y;
                scanf("%d %d", &x, &y);
                int ans = PointInPolygon(point(x, y), p, n);
                if(ans == 1) puts("No");
                else puts("Yes");
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    PHP之防御sql注入攻击的方式
    分享Java开发的利器-Lombok
    Linux最佳的云存储服务分析
    提升PHP编程效率的20个要素
    Java中常见的URL问题及解决方案
    配置CNPM-基础案例
    微软Skype Linux客户端全新发布
    jQuery 3.0最终版发布,十大新特性眼前一亮
    【风马一族_mysql】MySQL免安装版环境配置图文教程
    【风马一族_物理】维度空间的粒子
  • 原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5924883.html
Copyright © 2011-2022 走看看