判断点是否在多边形中

给一个 \(n\) 个点的多边形,给一个点 \(P\),问点 \(P\) 是否在多边形内(或多边形上)。

我们随便画一个多边形,随便在多边形内点一点,随便向外发一条射线,可以发现这条射线与多边形的交点个数为奇数。然后就做完了

对这条性质的简单证明:我们发现多边形内一点想要到外面,必须经过一条边,如果再进去,同样必须经过一条边,以此类推,可以得到结论。

还是有很多特殊情况的。例如射线经过多边形一个顶点的情况,或者这个点 \(P\) 本身就在多边形边上的情况等等。

所以我们的具体流程是这样的:

  1. 判断点 \(P\) 在不在多边形的边上,如果不在进行下一步
  2. 随机一个点 \(Q\),若点 \(PQ\) 与多边形的交点中有多边形的顶点,则重新随 \(Q\),直到满足条件
  3. 然后判断 \(PQ\) 与多边形有多少交点就好啦

时间复杂度:\(O(n)\)

代码:

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

using namespace std;

const double eps=1e-10;
const int N=100009;
int n;
struct Point
{
	double x,y;
	
	Point () {}
	Point (double X,double Y) : x(X),y(Y) {}
	Point operator - (const Point a)const { return Point(x-a.x,y-a.y); }
	double operator * (const Point a)const { return x*a.y-y*a.x; }
	void read() { scanf("%lf %lf",&x,&y); }
	void print() { printf("%.2lf %.2lf\n",x,y); }
}Q,P,a[N];

void init()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		a[i].read();
	P.read();
}

int nxt(int x) { return x==n?1:x+1; }

bool Point_In_Edge(Point A,Point B,Point C)
{
	double Minx=min(B.x,C.x),Maxx=max(B.x,C.x),Miny=min(B.y,C.y),Maxy=max(B.y,C.y);
	if(fabs((C-B)*(A-B))<eps&&A.x+eps>Minx&&A.x<Maxx+eps&&A.y+eps>Miny&&A.y<Maxy+eps)
		return 1;
	return 0;
}

bool Both_Point(Point P1,Point P2,Point P3,Point P4)
{
	if(!(max(P1.x,P2.x)+eps>=min(P3.x,P4.x)&&min(P1.x,P2.x)<=max(P3.x,P4.x)+eps))
		return 0;
	if(!(max(P1.y,P2.y)+eps>=min(P3.y,P4.y)&&min(P1.y,P2.y)<=max(P3.y,P4.y)+eps))
		return 0;
	if(((P2-P1)*(P3-P1))*((P2-P1)*(P4-P1))>eps)
		return 0;
	if(((P4-P3)*(P1-P3))*((P4-P3)*(P2-P3))>eps)
		return 0;
	return 1;
}

void work()
{
	for (int i=1;i<=n;i++)
		if(Point_In_Edge(P,a[i],a[nxt(i)]))
		{
			puts("Edge");
			return;
		}
	int qwq=1;
	while(qwq)
	{
		qwq=0;
		Q.x=(rand()<<15)+rand()+10000000;
		Q.y=(rand()<<15)+rand()+10000000;
		for (int i=1;i<=n;i++)
			if(Point_In_Edge(a[i],P,Q))
			{
				qwq=1;
				break;
			}
		if(qwq) continue;
		int sum=0;
		for (int i=1;i<=n;i++)
			sum+=Both_Point(a[i],a[nxt(i)],P,Q);
		if(sum&1) puts("in");
		else puts("out");
	}
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-06-28 00:51  With_penguin  阅读(163)  评论(0编辑  收藏  举报