HDU 1756 点在多边形内 Cupid's Arrow

该博客介绍了如何使用射线法判断一个点是否位于多边形内部,通过分析射线与多边形边界交点的奇偶性。文章特别提到了处理特殊情况,如边与射线共线以及边端点在射线上的情况。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1756

分析:[射线法]

          从已知点向x+oo远处向一水平射线,判断射线与多边形的交点个数,

          若为偶数,则点在多边形外,反之则在多边形内。

          注意几种特殊情况:

                 1、边和射线共线;

                 2、边的端点在射线上(上、下两端点只能考虑一个)

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iomanip>

using namespace std;
const int maxn=100000;
const int inf = 0xFFFFFFF;

int n;

struct point{
    double x,y;
    void read(){
        scanf("%lf%lf",&x,&y);
    }
}f[maxn];

struct segment {
    point a;
    point b;
}seg;

double cross(point A,point B,point C){///叉积
    return (B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y);
}

bool Dot_Segment(point D,segment R){ ///点在线段上
    if(D.x<min(R.a.x,R.b.x)||D.x>max(R.a.x,R.b.x)||
       D.y<min(R.a.y,R.b.y)||D.y>max(R.a.y,R.b.y))
        return false;
    if(cross(R.a,R.b,D))
        return false;
    return true;
}

bool Segmentcrossing(segment R,segment T){///线段相交
    return (cross(R.a,R.b,T.a)*cross(R.a,R.b,T.b)<0&&
            cross(T.a,T.b,R.a)*cross(T.a,T.b,R.b)<0);
}

bool work(point D){
    point M;
    M.x=inf;
    M.y=D.y;
    seg.a=D;
    seg.b=M;
    int num=0;
    for(int i=1;i<=n;++i){
        segment R;
        R.a=f[i]; R.b=f[i+1];
        if(Dot_Segment(D,R))///点在边上
            return true;
        if(cross(R.a,R.b,D)==0)///边和射线平行,即边水平
            continue;
        if(Dot_Segment(R.a,seg)){///边的上端点在射线上
            if(R.a.y>R.b.y) num++;
        }
        else if(Dot_Segment(R.b,seg)){
            if(R.a.y<R.b.y) num++;
        }
        else if(Segmentcrossing(R,seg))///射线和边相交
            num++;
    }
    return num%2;
}

int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;++i)
            f[i].read();
        f[n+1]=f[1];
        int m;
        scanf("%d",&m);
        while(m--){
            point D; D.read();
            if(work(D)) puts("Yes");
            else        puts("No");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值