[模板]计算几何

平面最近点对

将平面内点按\(x\)坐标排序,分治\(x\)坐标,设\(ret=min(f(l,mid),f(mid+1,r))\),将\(x\in[mid-ret,mid+ret]\)内的点按\(y\)坐标排序,算每个点与相邻的\(6\)个点的距离找最优解即可.

时间复杂度:\(O(nlogn)\).

#define N 100005
#define INF 1e15
struct point{
    double x,y;
}p[N];
inline double sqr(double k){
    return k*k;
}
inline double dis(point x,point y){
    return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
inline bool cmpx(point x,point y){
    if(x.x!=y.x) return x.x<y.x;
    return x.y<y.y;
}
inline bool cmpy(point x,point y){
    if(x.y!=y.y) return x.y<y.y;
    return x.x<y.x;
}
inline double min_d(int l,int r){
    double ret=INF;
    if(r-l<=20){
        for(int i=l;i<r;++i)
            for(int j=i+1;j<=r;++j)
                ret=min(ret,dis(p[i],p[j]));
        return ret;
    }
    int mid=l+r>>1;
    ret=min(min_d(l,mid),min_d(mid+1,r)); 
    while(p[l].x+ret<p[mid].x) ++l;
    while(p[r].x-ret>p[mid].x) --r;
    sort(p+l,p+1+r,cmpy);
    for(int i=l;i<r;++i)
        for(int j=min(r,i+6);j>i;--j)
            ret=min(ret,dis(p[i],p[j])); 
    sort(p+l,p+1+r,cmpx);
    return ret;
}
inline double min_dis(){
    sort(p+1,p+1+n,cmpx);
    return min_d(1,n);
}

推荐

http://www.cnblogs.com/xdruid/archive/2012/05/27/CP.html

凸包

时间复杂度:\(O(nlogn)\).

#define N 100005
#define eps 1e-13
struct point{
    int x,y;double an;
}a[N],v[N];
int n,u,vn;
inline double sqr(int k){
    return (double)(k*k);
}
inline point dec(point x,point y){
    return (point){x.x-y.x,x.y-y.y,0.0};
}
inline int mul(point x,point y){
    return x.x*y.y-y.x*x.y;
}
inline double dis(point x,point y){
    return sqrt(sqr(abs(x.x-y.x))+sqr(abs(x.y-y.y)));
}
inline bool cmp(point x,point y){
    if(fabs(x.an-y.an)<eps)
        return dis(x,a[1])>dis(y,a[1]); 
    return x.an<y.an;
} 
inline void convex(){
    u=1;
    for(int i=2;i<=n;++i)
        if((a[i].x<a[u].x)||(a[i].x==a[u].x&&a[i].y<a[u].y)) u=i;
    int tmp=a[u];a[u]=a[1];a[1]=tmp;
    for(int i=2;i<=n;++i)
        a[i].an=atan2(a[i].y-a[1].y,a[i].x-a[1].x);
    sort(a+2,a+1+n,cmp);
    v[++vn]=a[1];v[++vn]=a[2];a[++n]=a[1];
    for(int i=3;i<=n;++i){
        if(fabs(a[i].an-a[i-1].an)<eps) continue;
        while(vn>1&&mul(dec(a[i],v[vn-1]),dec(v[vn],v[vn-1]))>0) --vn;
        v[++vn]=a[i];
    }
} 

旋转卡壳

时间复杂度:\(O(n)\).

#define N 100005
struct point{
    int x,y;
}a[N];
int n;
inline point dec(point x,point y){
    return (point){x.x-y.x,x.y-y.y};
}
inline int mul(point x,point y){
    return x.x*y.y-x.y*y.x;
}
inline double sqr(int k){
    return (double)(k*k);
}
inline double dis(point x){
    return sqrt(sqr(x.x)+sqr(x.y));
}
inline int Next(int k){
    if(++k>n) return 1;
    return k;
}
inline double rorate(){
	point p;
    double di,dia=0.0;
    if(n==1) return dia;
    for(int i=1,j=2;i<=n;++i){
    	p=dec(a[Next(i)],a[i]);
        while(abs(mul(p,dec(a[j],a[i])))<abs(mul(p,dec(a[Next(j)],a[i]))))
            j=Next(j);
        dia=max(dia,max(dis(dec(a[i],a[j])),dis(dec(a[Next(i)],a[Next(j)]))));
    }
    return dia;
}

判断点是否在凸多边形内

inline point dec(point x,point y){
    return (point){x.x-y.x,x.y-y.y};
}
inline double mul(point x,point y){
    return x.x*y.y-y.x*x.y;
}
inline bool onseg(point p,point a,point b){  
    if(cmp(mul(dec(a,p),dec(b,p)))) return false;  
    return cmp(a.x-p.x)*cmp(b.x-p.x)<=0&&cmp(a.y-p.y)*cmp(b.y-p.y)<=0;
} 
inline int chk(point p){
    int cnt=0,k,d1,d2;
    for(int i=1;i<=n;++i){
        if(onseg(p,a[i],a[i+1])) return -1;
        k=cmp(mul(dec(a[i+1],a[i]),dec(p,a[i])));
        d1=cmp(a[i].y-p.y);d2=cmp(a[i+1].y-p.y);
        if(k>0&&d1<=0&&d2>0) ++cnt;
        if(k<0&&d2<=0&&d1>0) --cnt;
    }
    if(cnt) return 1;
    return 0;
}

半平面交

将半平面按极角排序(靠近法向量方向的半平面更小)
双端队列维护半平面交:顺序加入半平面,当队尾的2个半平面的交点在当前半平面外,删除队尾的半平面;当队头的2个半平面的交点在当前半平面外,删除队头的半平面.
\(P.S.\)形如\(ax+by+c\;\geq\;0\)的方程组的解\(A(x,y)\)满足条件\(\overrightarrow{BA}\;\times\;\overrightarrow{BC}\;\geq\;0(B,C\;\in\;ax+by+c=0)\)(\(ax+by+c<0\)反之)

typedef long double ld;
struct point{
    ld x,y;
}p[N];
struct line{
    point s,e;ld an;
}a[N],q[N];
int n,m,h,t;
inline point dec(point x,point y){
    return (point){x.x-y.x,x.y-y.y};
}
inline ld mult(point x,point y){
    return x.x*y.y-x.y*y.x;
}
inline bool cmp(line x,line y){
    if(x.an==y.an) return mult(dec(x.e,x.s),dec(y.s,x.s))>0;
    return x.an<y.an;
}
inline point inter(line a,line b){
    ld s1,s2,t;point ret;
    s1=mult(dec(b.e,a.s),dec(a.e,a.s));
    s2=mult(dec(a.e,a.s),dec(b.s,a.s));
    t=s2/(s1+s2);
    ret.x=b.s.x+(b.e.x-b.s.x)*t;
    ret.y=b.s.y+(b.e.y-b.s.y)*t;
    return ret;
}
inline bool chk(line x,line y,line z){
    point a=inter(x,y);
    return mult(dec(a,z.s),dec(z.e,z.s))>0;
}
inline bool hpi(int k){
	for(int i=1;i<=n;++i) 
	 	a[i].an=atan2(a[i].e.y-a[i].s.y,a[i].e.x-a[i].s.x);
	sort(a+1,a+1+n,cmp);
    h=1;t=0;
    for(int i=1;i<=n;++i){
        while(h<t&&chk(q[t],q[t-1],a[i])) --t;
        while(h<t&&chk(q[h],q[h+1],a[i])) ++h;
        q[++t]=a[i];
    }
    while(h<t&&chk(q[t],q[t-1],q[h])) --t;
    while(h<t&&chk(q[h],q[h+1],q[t])) ++h;
    return t-h+1>=3;
}
posted @ 2017-01-05 00:14  Aireen_Ye  阅读(143)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.