LightOj1190 - Sleepwalking(判断点与多边形的位置关系--射线法模板)

Posted 西瓜不懂柠檬的酸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOj1190 - Sleepwalking(判断点与多边形的位置关系--射线法模板)相关的知识,希望对你有一定的参考价值。

题目链接: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:\\n", 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

 

以上是关于LightOj1190 - Sleepwalking(判断点与多边形的位置关系--射线法模板)的主要内容,如果未能解决你的问题,请参考以下文章

题目1190:大整数排序

POJ 1190 生日蛋糕题解

程序集致命错误 LNK1190:找到无效修复,类型 0x0001

poj1190

poj1190 生日蛋糕(深搜+剪枝)

洛谷—— P1190 接水问题