题目:
给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部
题解:
网上有两种方法,这里写一种:射线法
大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方向)
如果交点个数为奇数的话就在内部,如果为偶数(包括0)就在外部
#include<cstdio> #include<algorithm> #include<cstring> #define N 105 using namespace std; int n,m; struct point//点(向量的结构体) { int x,y; point() {}//初始化 point (int _x,int _y) : x(_x),y(_y) {};//用一对坐标初始化点 inline point operator + (const point &rhs) const//向量加法 { return point(x+rhs.x,y+rhs.y); } inline point operator - (const point &rhs) const//向量减法 { return point(x-rhs.x,y-rhs.y); } inline int operator * (const point &rhs) const//向量叉乘 //向量叉乘的几何意义是以两个向量为邻边的平行四边形的有向面积 也就是|a|*|b|*sin<a,b> 这里的sin<a,b>决定了 //如果a,b是逆时针的,那么sin<a,b>大于0,有向面积大于0,反之<0 { return x*rhs.y-y*rhs.x; } friend inline int dot(const point &lhs,const point &rhs)//向量点乘 { return lhs.x*rhs.x+lhs.y*rhs.y; } }q; inline int check(const point &u,const point &v,const point &p)//判断点是不是在线段上 //u,v是线段端点,p是点 { int det=(u-p)*(v-p);//如果向量(u-p)*(v-p)==0就说明u,v,p共线(因为没面积) if (det!=0) return 0; int Dot=dot(u-p,v-p);//如果(u-p)点乘(v-p)<=0 就说明点在线段上 return Dot<=0; } struct polygon//多边形结构体 { int n; point p[N]; void init(int _n) { n=_n; for (int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); p[n]=p[0]; if (Area()<0) reverse(p,p+n);//通过判断多边形的有向面积来把点规范成逆时针的 p[n]=p[0]; } inline int Area() const //计算多边形的有向面积(如果点是逆时针的话就是正的,否则是负的) { int ret=0; for (int i=0;i<n;i++) ret+=p[i]*p[i+1]; return ret=0; } bool inner (const point &q)//判断点是不是在多边形内部 { int cnt=0; for (int i=0;i<n;i++) { if (check(p[i],p[i+1],q)) return 1;//如果点在线段上显然可以 int d1=p[i].y-q.y,d2=p[i+1].y-q.y; int det=(p[i]-q)*(p[i+1]-q); if ( (det>=0 && d1<0 && d2>=0) || (det<=0 && d1>=0 && d2<0)) ++cnt;//第一个条件是判断p在多边形内的时候,第二个是判断p在多边形外的时候 } return cnt&1; } }P; int main() { for (int tt=1;;tt++) { scanf("%d",&n); if (n==0) break; scanf("%d",&m); P.init(n); if (tt!=1) putchar(' '); printf("Problem %d: ",tt); while (m--) { scanf("%d%d",&q.x,&q.y); if (P.inner(q)) puts("Within"); else puts("Outside"); } } return 0; }