【计算几何】【凸包】【极角排序】【二分】Gym - 101128J - Saint John Festival
平面上n个红点,m个黑点,问你多少个黑点至少在一个红三角形内。
对红点求凸包后,转化为询问有多少个黑点在凸包内。
点在凸多边形内部判定,选定一个凸包上的点作原点,对凸包三角剖分,将其他的点极角排序之后,使用二分法就可以判定点在哪个剖分出来的三角形的夹角内,然后用叉积即可判定其在凸包内还是外,O(logn):
http://www.cnblogs.com/dream-wind/archive/2012/05/23/2514694.html
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; int n,m,K,O; struct Point{ ll x,y; double jiao; Point(){} Point(const ll &x,const ll &y){ this->x=x; this->y=y; } void Read(){ scanf("%lld%lld",&x,&y); } }; typedef Point Vector; Point p0,p; Vector operator - (const Point &a,const Point &b){ return Vector(a.x-b.x,a.y-b.y); } ll Cross(const Vector &a,const Vector &b){ return a.x*b.y-a.y*b.x; } bool cmp(const Point &a,const Point &b){ return a.x!=b.x ? a.x<b.x : a.y<b.y; } bool cm2(const Point &a,const Point &b){ return a.jiao<b.jiao; } Point ps[10010],qs[10010]; bool check(int mid){ return Cross(qs[mid]-p0,p-p0)<=0; } int main(){ // freopen("j.in","r",stdin); scanf("%d",&n); for(int i=0;i<n;++i){ ps[i].Read(); } sort(ps,ps+n,cmp); for(int i=0;i<n;++i){ while(K>1 && Cross(qs[K-1]-qs[K-2],ps[i]-qs[K-1])<=0){ --K; } qs[K++]=ps[i]; } for(int i=n-2,t=K;i>=0;--i){ while(K>t && Cross(qs[K-1]-qs[K-2],ps[i]-qs[K-1])<=0){ --K; } qs[K++]=ps[i]; } --K; for(int i=1;i<K;++i){ if(qs[i].y<qs[O].y || (qs[i].y==qs[O].y && qs[i].x<qs[O].x)){ O=i; } } p0=qs[O]; for(int i=0;i<K;++i){ qs[i].jiao=atan2((double)(qs[i].y-qs[O].y),(double)(qs[i].x-qs[O].x)); } for(int i=O;i<K-1;++i){ qs[i]=qs[i+1]; } --K; sort(qs,qs+K,cm2); scanf("%d",&m); int ans=0; for(int i=1;i<=m;++i){ p.Read(); if(Cross(p-p0,qs[0]-p0)<=0 && Cross(p-p0,qs[K-1]-p0)>=0){ int l=1,r=K-1; while(l<r){ int mid=(l+r>>1); if(check(mid)){ r=mid; } else{ l=mid+1; } } if(Cross(p-qs[l-1],qs[l]-qs[l-1])<=0){ ++ans; } } } printf("%d\n",ans); return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/