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;
}

时间: 2024-08-09 02:21:08

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

Cupid&#39;s Arrow---hdu1756(判断点与多边形的位置关系 模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1756 题意:中文题,套模板即可: /* 射线法:判断一个点是在多边形内部,边上还是在外部,时间复杂度为O(n): 射线法可以正确用于凹多边形: 射线法是使用最广泛的算法,这是由于相比较其他算法而言,它不但可以正 确使用在凹多边形上,而且不需要考虑精度误差问题.该算法思想是从点出 发向右水平做一条射线,计算该射线与多边形的边的相交点个数,当点不在 多边形边上时,如果是奇数,那么点就一定在多边形内部,否

计算几何线,点,多边形,位置关系较全模板

const double eps = 1e-6; int sgn(double x) { if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } struct Point { double x,y; Point(){} Point(double _x,double _y) { x = _x;y = _y; } Point operator -(const Point &b)const { return Point(

ZOJ1081 Points Within 点和多边形的位置关系

ZOJ1081 给一个点和一个多边形 判断点在多边形内(边上)还是在多边形外 在多边形外的点引一条射线必然穿过多边形的两条边 而在多边形内的点则不一定. 当然凹多边形有特殊情况 但是总能找到对应位置关系的边来抵消 #include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm>

判断两条直线的位置关系 POJ 1269 Intersecting Lines

两条直线可能有三种关系:1.共线     2.平行(不包括共线)    3.相交. 那给定两条直线怎么判断他们的位置关系呢.还是用到向量的叉积 例题:POJ 1269 题意:这道题是给定四个点p1, p2, p3, p4,直线L1,L2分别穿过前两个和后两个点.来判断直线L1和L2的关系 这三种关系一个一个来看: 1. 共线. 如果两条直线共线的话,那么另外一条直线上的点一定在这一条直线上.所以p3在p1p2上,所以用get_direction(p1, p2, p3)来判断p3相对于p1p2的关

UVA 10256 The Great Divide (凸包,多边形的位置关系)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34148 [思路] 凸包 求出红蓝点的凸包,剩下的问题就是判断两个凸包是否相离. 需要确定两点: 1)  凸包上线段是否相交->相交 2)  凸包上的点是否包含在另一个凸包里->内含. [代码] 1 #include<cmath> 2 #include<vector> 3 #include<cstdio> 4 #include&

Segments---poj3304(判断直线与线段的位置关系)

题目链接:http://poj.org/problem?id=3304 题意:给你n个线段,求是否有一条直线与所有的线段都相交,有Yes,没有No; 枚举所有的顶点作为直线的两点,然后判断这条直线是否和所有的线段相交即可;注意不能找两个相同的点作为直线上的两点: #include<iostream> #include<algorithm> #include<math.h> #include<string.h> #include<stdio.h>

[fzu 2273]判断两个三角形的位置关系

首先判断是否相交,就是枚举3*3对边的相交关系. 如果不相交,判断包含还是相离,就是判断点在三角形内还是三角形外.两边各判断一次. //http://acm.fzu.edu.cn/problem.php?pid=2273 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const double eps=1e-8; const

【模板】计几 射线法判断点是否在简单多边形内

1 // 2 //线段交点个数 3 int SegCross(Segment a,Segment b){ 4 double x1 = a.s.cross(a.e,b.s); 5 double x2 = a.s.cross(a.e,b.e); 6 double x3 = b.s.cross(b.e,a.s); 7 double x4 = b.s.cross(b.e,a.e); 8 if( b.e.OnLine(a.s,a.e) && b.s.OnSeg(a.s,a.e) || 9 b.s.O

hlg1306再遇攻击--射线法判断点是否在多边形内部

再遇攻击 Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 313(40 users) Total Accepted: 91(32 users) Rating:  Special Judge: No Description Dota中英雄技能攻击会有一个范围,现在释放一个技能给出他的攻击范围和目标英雄的位置,问是否能攻击到.攻击范围保证是一个多边型. Input 有多组测试数据 第一行输入1个整数n, 期中n代表攻击范围是给出的n个点