原文链接:点击打开链接
题目地址:http://www.cnblogs.com/try86/archive/2012/04/22/2465416.html
这一题,若点在边上,也将点看做成多边形内。
对于凸多边形有很多种方法判断点在多边形内,但若是凹多边形,则靠谱的方法不多,可以谷歌一下。
1)水平/垂直交叉点数判别法(适用于任意多边形包括凹凸边形)
注意到如果从P作水平向左的射线的话,如果P在多边形内部,那么这条射线与多边形的交点必为奇数,如果P在多边形外部,则交点个数必为偶数(0也在内)。所以,我们可以顺序考虑多边形的每条边,求出交点的总个数。还有一些特殊情况要考虑,具体见代码:
- //offset为多边形坐标上限
- //on_edge表示点在多边形边上时的返回值
- #include<iostream>
- #include<cmath>
- #include<cstring>
- #include<cstdio>
- #include<cstdlib>
- #include<time.h>
- using namespace std;
- const int offset=1000;
- const double eps=1e-8;
- struct Point{
- double x,y;
- }p[105];
- double cross(Point pi,Point pj,Point pk){ // (pi,pj)X(pi,pk)
- return (pj.x-pi.x)*(pk.y-pi.y)-(pj.y-pi.y)*(pk.x-pi.x);
- }
- int InPolygon(const Point *arr,const int &len,const Point &p,int on_edge=1){
- Point q;
- int i=0,counter;
- while(i<len){
- q.x=rand()+offset;//随机取一个足够远的点q
- q.y=rand()+offset;//以p为起点q为终点做射线L
- for(counter=i=0;i<len;i++){//依次对多边形的每条边进行考察
- if(fabs(cross(p,arr[i],arr[(i+1)%len]))<eps &&
- (arr[i].x-p.x)*(arr[(i+1)%len].x-p.x)<eps && (arr[i].y-p.y)*(arr[(i+1)%len].y-p.y)<eps)
- return on_edge; //点p在边上,返回on_edge
- else if(fabs(cross(p,q,arr[i]))<eps) break; //点arr[i]在射线pq上,停止本循环,另取q
- else if(cross(p,arr[i],q)*cross(p,arr[(i+1)%len],q)<-eps &&
- cross(arr[i],p,arr[(i+1)%len])*cross(arr[i],q,arr[(i+1)%len])<-eps)
- counter++;
- }
- }
- return counter&1;
- }
- int main(){
- int n,m;
- while(scanf("%d",&n)==1){
- for(int i=0;i<n;i++)
- scanf("%lf%lf",&p[i].x,&p[i].y);
- scanf("%d",&m);
- Point temp;
- while(m--){
- scanf("%lf%lf",&temp.x,&temp.y);
- if(InPolygon(p,n,temp))
- puts("Yes");
- else
- puts("No");
- }
- }
- return 0;
2)
角度和判别法
这个方法的原理是,多边形内一点(不含边上的点)到各相邻点的夹角之和为360度。
网上面很多人转载了这个方法,说是适用于任意多边形,其实不然,当然很多人的模板还是使用上面那种方法。。。
角度和判别法只适合凸多边形,对于这道题,针对这道题出组数据,点为顺时针给出:
4
0 0
5 10
10 0
5 5
1
5 0
这个多边形是凹多边形,点(5,0)并不在多边形内,但夹角之和却为360度,所以不能用这个方法
对于这个方法,如下代码提交,果断WA
- <pre name="code" class="cpp"><pre name="code" class="cpp"><pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre></pre>