题目大意:T when P belongs to the polygon or F otherwise
如果点P属于多边形那么输出T,反之输出F。
刚刚入门计算几何。都是自己摸索出来的,如果理解有偏差,望指点。
转角法。
我们把多边形每条边的转角加起来,如果是2pi,那么点在多边形内。
如果是Ipi,那么点在多边形的边界上。
如果是0,那么点在多边形外部。
如上图图一 转角为 <bac + < cad + < dab = 2pi
图二转角为 <feg + <geh + <hef = 0
转角法的代码实现为假设一条向右的射线。统计多边形穿过这条射线正反多少次。
逆时针加1,顺时针减1。
红色字体为大白上面的原话,我琢磨了一个下午一直卡壳。。
然后终于有了自己的见解。
例如题目的第二个例子。
具体看代码,图片已经附上帮组理解。
#include<iostream>
#include<cstdio>
#include<cmath>
#define FOR(i,m,n) for( int i = m; i<n;++i)
using namespace std;
//------------ 点结构,向量 ------------
struct NODE
{
double y,x;
NODE(double x= 0,double y= 0):x(x),y(y){};
};
typedef NODE vec;
vec operator - (NODE a,NODE b)
{
return vec(a.x - b.x,a.y -b.y );
}
//------------- dcmp -------------
const double eps = 1e-10;
int dcmp(double x)
{
if( fabs(x) < eps )
return 0;
else
return x < 0?-1:1;
}
//----------------------------
NODE point[1000+5];
NODE p;
//-------- X积 -------------
double cross( NODE a,NODE b,NODE c)
{
vec A (b.x - a.x,b.y- a.y);
vec B (c.x - a.x,c.y - a.y);
return A.x*B.y - A.y*B.x;
}
//--------- 点积 ----------
double dot(NODE a,NODE b,NODE c )
{
vec A (b.x - a.x,b.y- a.y);
vec B (c.x - a.x,c.y - a.y);
return A.x*B.x + A.y*B.y;
}
bool onsegment(NODE p,NODE a,NODE b)
{
return dcmp( cross( p,a,b)) == 0 && dcmp(dot(p,a,b))< 0;
/*
X积 == 0 --》 三点共线
点积 < 0 --> 点p属于线段ab
*/
}
int ispointinpoly(int n)
{
int wn =0;// wingding number
FOR(i,0,n)
{
if(onsegment(p,point[i],point[i+1]) )return -1;//onsegment
int k = dcmp( cross(point[i],point[i+1],p ) );
int d1 = dcmp(point[i].y - p.y);
int d2 = dcmp(point[i+1].y - p.y);
//printf(" i=%2d k=%2d d1=%2d d2=%2d ",i,k,d1,d2)
//p点引出一条向右的射线
if( k >0 && d1<=0 && d2>0)wn++;//射线逆时针穿过 i到i+1这两点间的线段 wn加一
if( k <0 && d2<=0 && d1>0)wn--;//顺时针则减一
//printf("wn=%2d\n",wn);n
}
if( wn!= 0)return 1;//indise
return 0;//outside
}
int main()
{
int n;
while( cin>>n && n )
{
FOR(i,0,n)
{
scanf("%lf %lf",&point[i].x,&point[i].y);
}
point[n] = point[0];//point[i+1]
cin>>p.x>>p.y;
if( ispointinpoly(n)==0 )puts("F");
else puts("T");
}
return 0;
}