计算几何基础

凸包算法

http://poj.org/problem?id=3348

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e5+11;
int n,m;
struct point{
	int x,y;
	point(){}
	point(int _x,int _y):
		x(_x),y(_y){}
	friend inline point operator -(const point A,const point B){
		return point(A.x-B.x,A.y-B.y);
	}
	friend inline int operator *(const point A,const point B){
		return A.x*B.y-A.y*B.x;
	}
	inline int norm(){
		return x*x+y*y;
	}
}p[N],q[N];
inline bool operator <(const point A,const point B){
	int det=(A-p[1])*(B-p[1]);	
	if(det!=0)return det>0;
	return (A-p[1]).norm()<(B-p[1]).norm();
}
inline void Graham(){
	int id=1;
	for(register int i=2;i<=n;++i)
		if(p[i].x<p[id].x||p[i].x==p[id].x&&p[i].y<p[id].y)
			swap(p[i],p[id]);
	sort(p+2,p+n+1);
	q[++m]=p[1];
	for(register int i=2;i<=n;++i){
		while(m>=2&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m;
		q[++m]=p[i];
	}
}
inline int Area(){
	int res=0;
	q[m+1]=q[1];
	for(register int i=1;i<=m;++i)
		res+=q[i]*q[i+1];
	return (res>>1);
}
int main(){
	scanf("%d",&n);
	for(register int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
	Graham();
	printf("%d
",Area()/50);
	return 0;
}

  

旋转卡壳

http://poj.org/problem?id=2187

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e5+11;
int n,m;
inline int max(int a,int b){
	return a>b?a:b;
}
struct point{
	int x,y;
	point(){}
	point(int _x,int _y):
		x(_x),y(_y){}
	friend inline point operator -(const point A,const point B){
		return point(A.x-B.x,A.y-B.y);
	}
	friend inline int operator *(const point A,const point B){
		return A.x*B.y-A.y*B.x;
	}
	inline int norm()const{
		return x*x+y*y;
	}
}p[N],q[N];
inline bool operator <(const point A,const point B){
	int det=(A-p[1])*(B-p[1]);	
	if(det!=0)return det>0;
	return (A-p[1]).norm()<(B-p[1]).norm();
}
inline void Graham(){
	int id=1;
	for(register int i=2;i<=n;++i)
		if(p[i].x<p[id].x||p[i].x==p[id].x&&p[i].y<p[id].y)
			swap(p[i],p[id]);
	sort(p+2,p+n+1);
	q[++m]=p[1];
	for(register int i=2;i<=n;++i){
		while(m>=2&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m;
		q[++m]=p[i];
	}
}
inline int nxt(int x){
	return x%m+1;
}
inline int area(const point A,const point B,const point C){
	return (B-A)*(C-A);
}
inline int query(){
	if(m==2)return (q[2]-q[1]).norm();
	int res=0;
	for(register int i=1,j=3;i<=m;++i){
		while(nxt(j)!=i&&area(q[i],q[i+1],q[j])<=area(q[i],q[i+1],q[nxt(j)]))j=nxt(j);
		res=max(res,(q[i+1]-q[j]).norm());
		res=max(res,(q[i]-q[j]).norm());
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(register int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
	Graham();
	printf("%d
",query());
	return 0;
}

  

BZOJ1069

http://www.lydsy.com/JudgeOnline/problem.php?id=1069

先做凸包,再枚举凸包的对角线,对于剩下的两个凸多边形做旋转卡壳

#include<cstdio>
#include<algorithm>
using namespace std;
typedef double db;
int n,m;
const int N=1e6+11;
struct point{
    db x,y;
    point(){}
    point(db _x,db _y):
        x(_x),y(_y){}
    friend inline point operator-(const point A,const point B){
        return point(A.x-B.x,A.y-B.y);
    }
    friend inline db operator*(const point A,const point B){
        return A.x*B.y-A.y*B.x;
    }
    inline db norm()const{
        return x*x+y*y;
    }
}p[N],q[N];
inline bool operator<(const point A,const point B){
    db det=(A-p[1])*(B-p[1]);
    if(det!=0)return det>0;
    return (A-p[1]).norm()<(B-p[1]).norm();
}
inline void Graham(){
    for(register int i=2;i<=n;++i)
        if(p[i].x<p[1].x||(p[i].x==p[1].x&&p[i].y<p[1].y))
            swap(p[i],p[1]);
    sort(p+2,p+n+1);
    q[++m]=p[1];q[++m]=p[2];
    for(register int i=3;i<=n;++i){
        while(m>1&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m;
        q[++m]=p[i];
    }
}
inline int nxt(int x){
    return x%m+1;
}
inline db abs(db x){
    return x>=0?x:-x;
}
inline db max(db a,db b){
    return a>=b?a:b;
}
inline db solve(){
    db ans=0;
    q[m+1]=q[1];
    for(register int i=1,k,l;i<=m;++i){
        l=nxt(nxt(k=nxt(i)));
        for(register int j=nxt(k);j<=m;++j){
            while(nxt(k)!=j&&abs((q[k]-q[i])*(q[j]-q[i]))<=abs((q[nxt(k)]-q[i])*(q[j]-q[i])))k=nxt(k);
            while(nxt(l)!=i&&abs((q[l]-q[i])*(q[j]-q[i]))<=abs((q[nxt(l)]-q[i])*(q[j]-q[i])))l=nxt(l);
            ans=max(ans,1.00*(abs((q[k]-q[i])*(q[j]-q[i]))+abs((q[l]-q[i])*(q[j]-q[i]))));
        }
    }
    return ans*1.00/2.00;
}
int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;++i)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    Graham();
    printf("%.3lf",solve());
    return 0;
}

  

BZOJ1185

http://www.lydsy.com/JudgeOnline/problem.php?id=1185

先做凸包,再枚举凸包的一条边,用旋转卡壳做出该边的平行线,然后用点积求矩形宽的极值(具有单调性)

复杂度O(n^2)

#include<cmath>
#include<algorithm>
#include<cstdio>
#define eps 1e-8
#define inf 1000000000
using namespace std;
double ans=1e60;
int n,top;
struct P{
    double x,y;
    P(){}
    P(double _x,double _y):x(_x),y(_y){}
    friend inline bool operator<(P a,P b){
        return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;
    }
    friend inline bool operator==(P a,P b){
        return fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps;
    }
    friend inline bool operator!=(P a,P b){
        return !(a==b);
    }
    friend inline P operator+(P a,P b){
        return P(a.x+b.x,a.y+b.y);
    }
    friend inline P operator-(P a,P b){
        return P(a.x-b.x,a.y-b.y);
    }
    friend inline double operator*(P a,P b){
        return a.x*b.y-a.y*b.x;
    }
    friend inline P operator*(P a,double b){
        return P(a.x*b,a.y*b);
    }
    friend inline double operator/(P a,P b){
        return a.x*b.x+a.y*b.y;
    }
    friend inline double dis(P a){
        return sqrt(a.x*a.x+a.y*a.y);
    }
}p[50005],q[50005],t[5];
inline bool cmp(P a,P b){
    double t=(a-p[1])*(b-p[1]);
    if(fabs(t)<eps)return dis(p[1]-a)-dis(p[1]-b)<0;
    return t>0;
}
inline void graham(){
    for(register int i=2;i<=n;++i)
        if(p[i]<p[1])
            swap(p[i],p[1]);
    sort(p+2,p+n+1,cmp);
    q[++top]=p[1];
    for(register int i=2;i<=n;++i){
        while(top>1&&(q[top]-q[top-1])*(p[i]-q[top])<eps)top--;
        q[++top]=p[i];
    }
    q[0]=q[top];
}
inline void RC(){
    int l=1,r=1,p=1;
    double L,R,D,H;
    for(register int i=0;i<top;++i){
        D=dis(q[i]-q[i+1]);
        while((q[i+1]-q[i])*(q[p+1]-q[i])-(q[i+1]-q[i])*(q[p]-q[i])>-eps)p=(p+1)%top;
        while((q[i+1]-q[i])/(q[r+1]-q[i])-(q[i+1]-q[i])/(q[r]-q[i])>-eps)r=(r+1)%top;
        if(i==0)l=r;
        while((q[i+1]-q[i])/(q[l+1]-q[i])-(q[i+1]-q[i])/(q[l]-q[i])<eps)l=(l+1)%top;
        L=(q[i+1]-q[i])/(q[l]-q[i])/D,R=(q[i+1]-q[i])/(q[r]-q[i])/D;
        H=(q[i+1]-q[i])*(q[p]-q[i])/D;
        if(H<0)H=-H;
        double tmp=(R-L)*H;
        if(tmp<ans){
            ans=tmp;
            t[0]=q[i]+(q[i+1]-q[i])*(R/D);
            t[1]=t[0]+(q[r]-t[0])*(H/dis(t[0]-q[r]));
            t[2]=t[1]-(t[0]-q[i])*((R-L)/dis(q[i]-t[0]));
            t[3]=t[2]-(t[1]-t[0]);
        }
    }
}
int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;++i)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    graham();
    RC();
    printf("%.5lf
",ans);
    int fir=0;
    for(register int i=1;i<=3;++i)
        if(t[i]<t[fir])
            fir=i;
    for(register int i=0;i<=3;++i)
        printf("%.5lf %.5lf
",fabs(t[(i+fir)%4].x),fabs(t[(i+fir)%4].y));
    return 0;
}

  

原文地址:https://www.cnblogs.com/Stump/p/8410883.html