Description
给出l个大点和s个小点,问有多少小点被三个大点组成的三角形覆盖
Input
第一行一整数l表示大点的数量,之后l行每行两个整数x,y表示该大点的横纵坐标,然后输入一整数s表示小点数量,最后s行每行两个整数x和y表示该小点的横纵坐标(3<=l<=10000,1<=s<=50000,0<=x,y<=2^30)
Output
输出满足条件的小点的数量
Sample Input
8
3 4
2 8
5 4
1 8
4 7
3 10
11 2
7 3
6
5 12
3 7
3 3
4 5
0 4
2 6
Sample Output
3
Solution
只要一个小点在由这些大点组成的凸包中那么一定存在三个大点组成一个三角形覆盖这个小点,所以首先对l个大点用Graham扫描法求一遍凸包,以0点为三角形一顶点,相邻两凸包上点作为另外两个顶点,这样就对整个凸包进行了三角剖分,之后对于每个小点x,二分其属于哪个三角形,假设其属于0,i,j=i+1三点组成的三角形,那么ox^oi和ox^oj(^表示叉乘)必然异号,那么x就在oi和oj为两个方向的锥内,之后还要判断x点是否在三角形oij里,这时判断向量ix是否在向量ij的逆时针方向即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 11111
const double eps=1e-8;
const double PI=acos(-1.0);
struct Point
{
double x,y;
double k;
Point(){}
Point(double _x,double _y)
{
x=_x;y=_y;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
double operator ^(const Point &b)const
{
return x*b.y-y*b.x;
}
double operator *(const Point &b)const
{
return x*b.x+y*b.y;
}
};
int sgn(double x)
{
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
double dist(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
Point list[maxn];
int Stack[maxn],top;
//相对于list[0]的极角排序
bool _cmp(Point p1,Point p2)
{
double tmp=(p1-list[0])^(p2-list[0]);
if(sgn(tmp)>0)return true;
else if(sgn(tmp)==0&&sgn(dist(p1,list[0])-dist(p2,list[0]))<=0)return true;
else return false;
}
void Graham(int n)
{
Point p0;
int k=0;
p0=list[0];
//找最下边的一个点
for(int i=1;i<n;i++)
{
if((p0.y>list[i].y)||(p0.y==list[i].y&&p0.x>list[i].x))
{
p0=list[i];
k=i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n==1)
{
top=1;
Stack[0]=0;
return;
}
if(n==2)
{
top=2;
Stack[0]=0;
Stack[1]=1;
return ;
}
Stack[0]=0;
Stack[1]=1;
top=2;
for(int i=2;i<n;i++)
{
while(top>1&&sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]]))<=0)
top--;
Stack[top++]=i;
}
}
int L,S;
Point s;
bool check(Point s)
{
int l=1,r=top-2;
while(l<=r)
{
int mid=(l+r)/2;
Point a=list[Stack[0]],b=list[Stack[mid]],c=list[Stack[mid+1]];
double t1=(b-a)^(s-a);
double t2=(c-a)^(s-a);
if(t1>=0&&t2<=0)
{
double t=(c-b)^(s-b);
if(t>=0)return 1;
return 0;
}
if(t1<0)r=mid-1;
else l=mid+1;
}
return 0;
}
int main()
{
while(~scanf("%d",&L))
{
for(int i=0;i<L;i++)scanf("%lf%lf",&list[i].x,&list[i].y);
Graham(L);
int ans=0;
scanf("%d",&S);
while(S--)
{
scanf("%lf%lf",&s.x,&s.y);
if(check(s))ans++;
}
printf("%d\n",ans);
}
return 0;
}