Description
方师傅来到了一个二维平面。他站在原点上,觉得这里风景不错,就建了一个房子。这个房子是n个点的凸多边形
,原点一定严格在凸多边形内部。有m个人也到了这个二维平面。现在你得到了m个人的坐标,你要判断这m个人中
有多少人在房子内部。点在凸多边形边上或者内部都认为在房子里面。
题解:
O(logn) 判断一个点是否在凸包内的方法:从第一个点向其他点连线,把这个凸包分成 n−2 个三角形,然后二分,用叉积判断当前点是否在三角形内。总时间复杂度 O(mlogn) 。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int maxm=200010;
struct point{double x,y;}p1[maxn],p2[maxm];
double multi(point p1,point p2,point p0)
{
double x1=p1.x-p0.x,y1=p1.y-p0.y;
double x2=p2.x-p0.x,y2=p2.y-p0.y;
return x1*y2-x2*y1;
}
int n,m,ans=0;
bool check(point p1,point p2,point p0)//已知3点在同一直线,判断p0是否在p1、p2的线段上
{
bool tfx=false,tfy=false;
if((p1.x<=p0.x&&p0.x<=p2.x)||(p2.x<=p0.x&&p0.x<=p1.x))tfx=true;
if((p1.y<=p0.y&&p0.y<=p2.y)||(p2.y<=p0.y&&p0.y<=p1.y))tfx=true;
return tfx&tfy;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf%lf",&p1[i].x,&p1[i].y);
scanf("%d",&m);
int now=1;
p2[0].x=p2[0].y=0.0;
for(int i=1;i<=m;i++)
{
scanf("%lf%lf",&p2[i].x,&p2[i].y);
p2[i].x=p2[i-1].x+now*p2[i].x;
p2[i].y=p2[i-1].y+now*p2[i].y;
if(multi(p1[1],p1[2],p2[i])<0||multi(p1[1],p1[n],p2[i])>0){now=-1;continue;}
if(multi(p1[1],p1[2],p2[i])==0)
{
if(check(p1[1],p1[2],p2[i]))now=1,ans++;
else now=-1;
continue;
}
if(multi(p1[1],p1[n],p2[i])==0)
{
if(check(p1[1],p1[n],p2[i]))now=1,ans++;
else now=-1;
continue;
}
int l=3,r=n;
while(l<=r)
{
int mid=l+r>>1;
if(multi(p1[1],p1[mid],p2[i])<0)r=mid-1;
else l=mid+1;
}
if(multi(p1[l],p1[l-1],p2[i])<=0)now=1,ans++;
else now=-1;
}
printf("%d",ans);
}