省选模板复习—【计算几何】

头文件:

const double eps=1e-8;
const double pi=acos(-1);
inline double P(double x){
	return x*x;
}
inline int sign(double x){
	return fabs(x)<eps?0:(x>0?1:-1);
}
struct point{
	double x,y;
	point(double _x=0,double _y=0):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 point operator -(const point &a,const	point &b){
		return point(a.x-b.x,a.y-b.y);
	}
	friend inline point operator *(const point &a,const double &b){
		return point(a.x*b,a.y*b);
	}
	friend inline point operator /(const point &a,const double &b){
		return point(a.x/b,a.y/b);
	}
	friend inline double operator ^(const point &a,const point &b){
		return a.x*b.x+a.y*b.y;
	}
	friend inline double operator *(const point &a,const point &b){
		return a.x*b.y-a.y*b.x;
	}
	friend inline bool operator <(const point &a,const point &b){
		return (a.x==b.x)?a.y<b.y:a.x<b.x;
	}
	inline void rotate(double t){
		double px=x,py=y;
		x=px*cos(t)-py*sin(t),y=px*sin(t)+py*cos(t);
	}
	inline double ang(){
		return atan2(y,x);
	}
	inline double calc(){
		return P(x)+P(y);
	}
}
struct line{
	point s,e;int id;
	double rad;
	line(){}
	line(point x,point y){
		s=x,e=y,rad=(y-x).ang();
	}
	friend inline bool operator <(const line &a,const line &b){
		return sign(a.rad-b.rad)?sign(a.rad-b.rad)<0:sign((a.e-a.s)*(b.e-a.s))>0;
	}
}

凸包

(POJ3348)

point p[N],q[N];
int n,tot,top;
inline bool comp(const point &a,const point &b){
	double k=(a-p[1])*(b-p[1]);
	return sign(k)?k>0:(a-p[1]).calc()<(b-p[1]).calc();//关于长度,短的在前
}
void graham(){
	for(int i=2;i<=n;i++){
		if(p[i]<p[1])swap(p[1],p[i]);
	}
	sort(p+2,p+n+1,comp);//从2、
	q[top=1]=p[1];
	for(int i=2;i<=n;i++){
		while(top>=2&&sign((p[i]-q[top-1])*(q[top]-q[top-1]))>=0)top--;//相同也弹出
		q[++top]=p[i];
	}
	q[top+1]=q[1];
}
inline int area(){
	int res=0;
	for(int i=1;i<=top;i++)res+=q[i]*q[i+1];
	return res/100;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
	graham();
	cout<<area();
}

旋转卡壳

(POJ2187)

inline int nxt(int x){
	return x==m?1:x+1;
}
inline double area(const point &a,const point &b,const point &c){
	return (b-a)*(c-a);
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
	graham();
	q[m+1]=q[1];
	for(int i=1,j=1;i<=m;i++){
		while((nxt(j)!=i)&&sign((area(q[i],q[i+1],q[j+1])-area(q[i],q[i+1],q[j])))>=0)j=nxt(j);//注意判边界
		ans=max(ans,(q[j]-q[i]).calc());
		ans=max(ans,(q[j]-q[i+1]).calc());//似乎不加这句话过不了…,反正加了不会错
	}
	cout<<ans<<'\n';
}

半平面交

(BZOJ2618)

point a[N],b[N];
line p[N],q[N];
inline point insec(const line &a,const line &b){
    double t1=(b.s-a.s)*(a.e-a.s),t2=(a.e-a.s)*(b.e-a.s);
    double k=(t1)/(t1+t2);
    return (b.s+((b.e-b.s)*k));
}
inline double K(int i){
	return (q[i].e.y-q[i].s.y)/(q[i].e.x-q[i].s.x);
}
inline double B(int i){
	return q[i].s.y-K(i)*q[i].s.x;
}
inline bool comp(const line &a,const line &b,const line &c){
    return sign((c.e-c.s)*(insec(a,b)-c.s))<0;
}
int hd,tl,tot,n,m;
int ans[N];
inline void half(){
    sort(p+1,p+n+1);
    for(int i=1;i<=n;i++){
        if(sign(p[i].rad-p[i-1].rad))tot++;
        p[tot]=p[i];
    }
    q[1]=p[1],q[2]=p[2],hd=1,tl=2;
    for(int i=3;i<=tot;i++){
        while(hd<tl&&comp(q[tl-1],q[tl],p[i]))tl--;  //注意先tail后head不能反    
        while(hd<tl&&comp(q[hd],q[hd+1],p[i]))hd++;
        q[++tl]=p[i];
    }
    while(hd<tl&&comp(q[tl-1],q[tl],q[hd]))tl--;
    while(hd<tl&&comp(q[hd],q[hd+1],q[tl]))hd++;
    tot=0,q[tl+1]=q[hd];
    for(int i=hd;i<=tl;i++)b[++tot]=insec(q[i],q[i+1]);
}
inline double area(){
    double res=0;
    for(int i=1;i<=tot;i++){
        res+=b[i]*b[i%tot+1];
    }
    return res/2;
}
int main(){
    m=read();
    for(int i=1;i<=m;i++){
        int k=read();
        for(int j=1;j<=k;j++)a[j].x=read(),a[j].y=read();
        for(int j=1;j<=k;j++)p[++n]=line(a[j],a[j%k+1]);
    }
    half();
    printf("%.3lf",area());
}

经典题目

动态凸包

最小矩阵覆盖

圆的周长并

圆的凸包(等周长)

最小圆覆盖

posted @ 2019-04-10 15:40  Stargazer_cykoi  阅读(155)  评论(0编辑  收藏  举报