[学习][ZOJ1081]点、直线关系 Points Within

题目背景
ZOJ1081

题目描述
Statement of the Problem Several drawing applications allow us to draw polygons and almost all of them allow us to fill them with some color. The task of filling a polygon reduces to knowing which points are inside it, so programmers have to colour only those points.
You’re expected to write a program which tells us if a given point lies inside a given polygon described by the coordinates of its vertices. You can assume that if a point is in the border of the polygon, then it is in fact inside the polygon.

题目大意
给你一个多边形的顶点和其他几个点,判断这几个点在多边形内还是外。

输入格式
输入文件可能包含多组数据。 每组数据包括:(i)一行包含整数N( 0<N<100 )和M,分别是多边形的顶点数和要测试的点数。 (ii)接下来N行,每行包含描述多边形顶点坐标的一对整数; (iii)接下来M行,每行包含一对整数表示询问的点的坐标。 你可以假设:顶点都是不同的; 输入中的连续顶点在多边形中相邻; 最后一个顶点与第一个顶点相邻; 并且所得到的多边形是简单的,即,每个顶点恰好两个边缘入射,并且两个边缘仅在其公共端点相交。 最后一个实例后跟一行为0(零)。

输出格式
对于输入中的第i个实例,您必须在输出中使用短语“Problem i:”写入一行,后跟几行,每个测试点都按照输入中的顺序排列。 这些行中的每一行应该读取“Within”或“Outside”,具体取决于测试的结果。 两个连续实例的输出应提行分隔。

样例数据
输入

3 1
0 0
0 5
5 0
10 2
3 2
4 4
3 1
1 2
1 3
2 2
0

输出

Problem 1:
Outside
Problem 2:
Outside
Within

2017.5.20
我必须声明一下:
本来我正在学习计算几何,这道题是例题,在网上找题解时,发现了这个:http://blog.csdn.net/weinierzui/article/details/24590969
觉得这个代码特别短,于是……研究了一下午(本来是学射线法来着),全篇博文只有一个“绕数”吸引了我的眼球,在网上找了半天绕数一无所获……
后来发现大佬貌似用了一种叫“弧长法”的算法,到现在还不是很领悟……
膜一下写代码的大佬orz
把我的半成品放下面了,以后如果又弄懂了些再来改:

2017.5.27
经过指点,发现其实这就是普通射线法,真的好短:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

const int maxn=210;

struct node{
    int x,y;
}a[maxn],b;
int n,m;

int getint()//读入优化 
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;ch>='0'&&ch<='9';ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-'0';
    return sum*f;
}

/*
点乘原理:
若在线段上,说明point到linestart和lineend是两条方向相反的向量,
或是有一个0向量(在端点上时),故肯定<=0 
若在线段外,是两个同向非零向量,显然>0,证毕 
*/ 
int inl(node point,node linestart,node lineend)//向量点乘判断 
{
    int x1=linestart.x-point.x;
    int y1=linestart.y-point.y;
    int x2=lineend.x-point.x;
    int y2=lineend.y-point.y;
    return x1*x2+y1*y2; 
}

/*
叉乘原理:
把题目围成的多边形用首尾相接的向量表示,
若向量向上穿过射线,d<0
若向量向下穿过射线,d>0
向量在射线上,d=0 
*/ 
int cross(node point,node linestart,node lineend)//向量叉乘判断
{
    int x1=point.x-linestart.x;
    int y1=point.y-linestart.y;
    int x2=lineend.x-linestart.x;
    int y2=lineend.y-linestart.y;
    return x1*y2-x2*y1;
}

bool check(node b)
{
    int sum=0;
    for(int j=0;j<n;++j)
    {
        int d=cross(b,a[j],a[(j+1)%n]);//判断在/不在边所在的直线上 
        if(d==0)//点在直线上 
        {
            if(0>=inl(b,a[j],a[(j+1)%n]))//判断在/不在线段上 
                return true;
        }
        //竟然是普通的射线法!!! 
        int d1=a[j].y-b.y;
        int d2=a[(j+1)%n].y-b.y;
        //如果水平射线根本没有穿过某边,则不用管
        //若点在圆外,则肯定穿过偶数条边,并且一半向上穿过,一半向下穿过,则最后sum一定为0,其他情况便是在圆内        
        if(d<0&&d1<=0&&d2>0)
            sum++;
        if(d>0&&d2<=0&&d1>0)
            sum--;
    }

    if(sum!=0)
        return true;
    else
        return false;
}

int main()
{
    //freopen("lx.in","r",stdin);

    for(int tt=1;;++tt)
    {
        n=getint();
        if(n==0) break;
        m=getint();
        for(int i=0;i<n;++i)
        {
            a[i].x=getint();
            a[i].y=getint();
        }

        if(tt!=1)
            printf("\n");
        printf("Problem %d:\n",tt);
        while(m--)
        {
            b.x=getint();b.y=getint();
            if(check(b))//判断 
                printf("Within\n");
            else
                printf("Outside\n");
        }
    }

    return 0;
}

本题结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值