zoukankan      html  css  js  c++  java
  • 判断点是否在多边形中

    给一个 (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
    ",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;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    (转)一次棘手的rootvg更换硬盘处理过程
    mysql:服务器错误代码
    (转)运行跟踪格式化程序
    (转)InnoDB存储引擎MVCC实现原理
    (转)漫谈JVM
    (转)mysql、innodb和加锁分析
    (转)DB2和 Oracle的并发控制(锁)比较
    (转)Mysql主从复制搭建及详解
    BigDecimal 、BigInteger
    Date、DateFormat、SimpleDateFormat、Calendar
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13200744.html
Copyright © 2011-2022 走看看