我的acm几何模板

部分代码来源于kuangbin的几何模板

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
//`Compares a double to zero`
int sgn(double x){
	if(fabs(x) < eps)return 0;
	if(x < 0)return -1;
	else return 1;
}
struct Point{
	double x,y;
	Point(){}
	Point(double _x,double _y){
		x = _x;
		y = _y;
	}
	//叉积 
	double operator ^(Point b){
		return x*b.y-y*b.x;
	}
	double cross(Point b,Point c){
		return (b.x-x)*(c.y-y)-(b.y-y)*(c.x-x);
	}
	//点积
	double operator *(Point b){
		return x*b.x+y*b.y;
	} 
	double dot(Point b,Point c){
		return (b.x-x)*(c.x-x)+(b.y-y)*(c.y-y);
	}
	//两点间的距离 
	double distance(Point b){
		return hypot(x-b.x,y-b.y);
	}
	//优先x然后y的坐标比较与排序 
	bool operator < (Point b)const{
		return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
	}
	//减 
	Point operator -(const Point &b)const{
		return Point(x-b.x,y-b.y);
	}
	//判断相等 
	bool operator == (Point b)const{
		return sgn(x-b.x)==0&&sgn(y-b.y)==0;
	}
	//加 
	Point operator + (const Point & b)const{
		return Point(b.x+x,b.y+y);
	}
	//除double 
	Point operator /(const double &b)const {
		return Point(x/b,y/b);
	}
	//乘double 
	Point operator *(const double &b)const {
		return Point(x*b,y*b);
	}
	//向量逆时针旋转90度 
	Point rotleft(){
		return Point(-y,x);
	}
	//向量顺时针旋转90度
	Point rotright(){
		return Point(y,-x);
	} 
	//`绕着p点逆时针旋转angle`
	Point rotate(Point p,double angle){
		Point v = (*this) - p;
		double c = cos(angle), s = sin(angle);
		return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);
	}
	//返回以当前点this为起点 this->b为方向 长度为r的点 
	Point mytrunc(Point b,double r){
		double lens = distance(b);
		Point unit = (b-(*this))/lens;
		return Point (*this)+unit*r;
	} 
	double linedis(Point b,Point c){
		return fabs(cross(b,c))/b.distance(c);
	} 
};
struct Line{
	Point s,e;
	Line(){}
	Line(Point _s,Point _e){
		s = _s;
		e = _e;
	}
	//直线和直线
	//0重合
	//1平行 
	//2相交 
	int linecorssline(Line v){
		if(sgn((e-s)^(v.e-s))==0&&sgn((e-s)^(v.s-s))==0) return 0;
		else if(sgn(((e-s)^(v.e-s))-((e-s)^(v.s-s)))==0) return 1;
		return 2;	
	}
	//求两直线的交点 
	Point crosspoint(Line v){
		double a1 = (v.e-v.s)^(s-v.s);
		double a2 = (v.e-v.s)^(e-v.s);
		return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
	}
	//线段之间的关系
	//2 规范相交
	//1 不规范相交(交于某一线段的端点)
	//0 不相交 
	int segecross(Line v){
		Point a=s,b=e,c=v.s,d=v.e;
		int d1=sgn(a.cross(b,c));
		int d2=sgn(a.cross(b,d));
		int d3=sgn(c.cross(d,a));
		int d4=sgn(c.cross(d,b));
		if((d1^d2)==-2&&(d3^d4)==-2) return 2;
		return(d1==0&&sgn(c.dot(a,b))<=0)||
		(d2==0&&sgn(d.dot(a,b))<=0)||
		(d3==0&&sgn(a.dot(c,d))<=0)||
		(d4==0&&sgn(b.dot(c,d))<=0);
	}
	//点到线段的距离(最小距离) 
	double point_to_seg(Point a,Point b,Point c){
		if(b==c) return a.distance(c); 
		if(sgn(b.dot(a,c))<0||sgn(c.dot(a,b))<0)
		return min(a.distance(b),a.distance(c));
		return a.linedis(b,c);
	} 
	//线段到线段的最小距离
	double seg_to_seg(Line v){
		return min(min(point_to_seg(s,v.s,v.e),point_to_seg(e,v.s,v.e)),min(point_to_seg(v.s,s,e),point_to_seg(v.e,s,e)));
	}
};

//////////////////圆 
struct circle{
	Point p;
	double r;
	circle (Point _p,double _r){
		p = _p;
		r = _r;
	}
	circle(Point a,Point b,Point c){
		Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
		Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
		p = u.crosspoint(v);
		r = p.distance(a);
	}
	//求两圆的公切线 
	//需要用到Point里面的mytrunc,distance 
	//测试 UVA10674 
	bool flag=false;//判断两圆是否进行过交换 
	Line ans[6];//所得的切线 
	int gettange(circle v){
		Point a = p,Point b = v.p;double r1 = r,r2 = v.r;
		int cnt=0;
		if(a==b&&!sgn(r1-r2)) return -1;//重合 无数公切线
		if(sgn(a.x-b.x)>0) swap(a,b),swap(r1,r2),flag=true;
		double lens = a.distance(b),d = fabs(r1-r2);
		if(sgn(lens-d)<0) return 0;//内含 无公切线 
		else if(sgn(lens-d)==0){//内切 一条公切线 
			if(sgn(r1-r2)>0) //注意判断半径 
			ans[1]=Line(a.mytrunc(b,r1),a.mytrunc(b,r1));
			else ans[1]=Line(b.mytrunc(a,r2),b.mytrunc(a,r2));
			return 1;
		}
		double ta,tb;//相离、外切、相交都有的两条切线 
		if(sgn(r1-r2)>0) ta=acos(d/lens),tb=pi-ta;  
		else tb=acos(d/lens),ta=pi-tb;
		cnt++;ans[cnt].s=a.mytrunc(b.rotate(a,ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,-tb),r2);
		cnt++;ans[cnt].s=a.mytrunc(b.rotate(a,-ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,tb),r2);
		if(!sgn(lens-r1-r2)){//外切 多一条 
			cnt++;ans[cnt]=Line(a.mytrunc(b,r1),a.mytrunc(b,r1));
		}else if(sgn(lens-r1-r2)>0){//相离 多两条 
			double l1=(lens/(r1+r2))*r1;
			double l2=lens-l1;
			ta=acos(r1/l1),tb=acos(r2/l2);
			++cnt;ans[cnt].s=a.mytrunc(b.rotate(a,ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,tb),r2);
			++cnt;ans[cnt].s=a.mytrunc(b.rotate(a,-ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,-tb),r2);		
		}
		return cnt; //返回切线的个数 
	}
	//最小圆覆盖 pt是点集 n是点数 
	circle(Point pt[],int n){
	circle o(Point(0,0),0);
	random_shuffle(pt+1,pt+1+n);
	for(int i = 1; i <= n; i++){
			if(sgn(o.r-o.p.distance(pt[i]))<0){
				o=circle(pt[i],0);
				for(int j = 1; j < i; j++){
					if(sgn(o.r-o.p.distance(pt[j]))<0){
						o.p=(pt[i]+pt[j])/2.0,o.r=o.p.distance(pt[i]);
						for(int k = 1; k < j; k++){
							if(sgn(o.r-o.p.distance(pt[k]))<0)
							o=circle(pt[k],pt[i],pt[j]);
						}
					} 
				}
			}
		}
		(*this)=o;
	} 
}; 

////////////////////////凸包
struct polygon{
	int n;
	Point p[maxp];
	//极角排序的比较函数 
	struct cmp{
		Point p;
		cmp(const Point &p0){p = p0;}
		bool operator()(const Point &aa,const Point &bb){
			Point a = aa, b = bb;
			int d = sgn((a-p)^(b-p));
			if(d == 0){
				return sgn(a.distance(p)-b.distance(p)) < 0;
			}
			return d > 0;
		}
	};
	//`进行极角排序`
	//`首先需要找到最左下角的点`
	//`需要重载号好Point的 < 操作符(min函数要用) `
	void norm(){
		Point mi = p[0];
		for(int i = 1;i < n;i++)mi = min(mi,p[i]);
		sort(p,p+n,cmp(mi));
	}
	//凸包算法 返回凸包的点个数 
	//此算法得到的凸包顶点会按照逆时针排序 
	int Graham(Point q[]){
		int top = -1;
		sort(p,p+n);
		q[++top]=p[0];q[++top]=p[1];
		for(int i = 2; i < n; i++){
			while(top>=1&&cross(q[top-1],q[top],p[i])<0) top--;//加上等于号得到纯净(不稳定凸包) 
			q[++top]=p[i];
		}
		int tp=top;
		for(int i = n-2; i >= 0; i--){
			while(top>=tp+1&&cross(q[top-1],q[top],p[i])<0) top--;
			q[++top]=p[i];
		}
		return top;
	} 
	////////////////////////////旋转卡壳
	//凸包直径 
		double diameter(){
		if(n==1) return 0;
		int r = 1;
		double ans = p[0].distance(p[r]);
		for(int i = 0; i < n; i++){
			Point p1=p[i],p2=p[(i+1)%n];
			double s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
			while(sgn(s1-s2)<0){
				r=(r+1)%n;
				s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
			}
			if(sgn(ans-p1.distance(p[r]))<0) ans=p1.distance(p[r]);
			if(sgn(ans-p2.distance(p[r]))<0) ans=p2.distance(p[r]); 
		}
		return ans;
	} 
	//凸包宽度
	double width(){
		double ans = 1e9+100;
		if(n<=2) return 0;
		int r = 2;
		for(int i = 0; i < n; i++){
			Point p1=p[i],p2=p[(i+1)%n];
			double s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
			while(sgn(s1-s2)<0){
				r=(r+1)%n;
				s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
			}
			ans=min(ans,p[r].linedis(p1,p2));
		}
		return ans;
	}  
	//两多边形之间的最近最远距离
	//需要用到线段到线段最短距离 seg_to_seg(求最近的时候) 
	double getmindis(polygon b){
		polygon a = (*this);
		int i=0,j=0;
		Point e=a.p[0],f=b.p[0];
		for(int o = 1; o < a.n; o++)
			if(a.p[o].y<e.y) e=a.p[o],i=o;
		for(int o = 1; o < b.n; o++)
			if(b.p[o].y>f.y) f=b.p[o],j=o;
		a.p[a.n]=a.p[0],b.p[b.n]=b.p[0];
		double ans = inf; 
		for(int o = 0; o < a.n; o++){
			while(sgn(a.p[i+1].cross(b.p[j+1],a.p[i])-a.p[i+1].cross(b.p[j],a.p[i]))>0) j=(j+1)%b.n;
			ans=min(ans,seg_to_seg(a.p[i],a.p[i+1],b.p[j],b.p[j+1]));
			//最远距离就改成max 
			i=(i+1)%a.n;
		}
		return ans;
	}
	//`判断点和任意多边形的关系`(凹凸顺逆皆可) 
	//` 3 点上`
	//` 2 边上`
	//` 1 内部`
	//` 0 外部`
	int relationpoint(Point s){
		int ans = 0;
		for(int i = 0; i < n; i++){
			if(s==p[i]) return 3;
			int d = sgn(p[(i+1)%n].cross(s,p[i])); 
			if(d==0) {if(s.dot(p[i],p[(i+1)%n])<=0) return 2;}
			else {
				int u = sgn(p[i].y-s.y);
				int v = sgn(p[(i+1)%n].y-s.y);
				if(d > 0 && u < 0 && v >= 0)ans++;
				if(d < 0 && v < 0 && u >= 0)ans--;
			}
			//printf("ans=%d\n",ans);
		}
		return ans!=0;
	} 
};



////////////////////平面最近点对
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1e5+100;
int n;
struct Point{
	double x,y;
	Point(){}
	Point(double _x,double _y){
		x = _x;
		y = _y;
	}
	double dis(Point b){
		return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
	}
	void input(){
		scanf("%lf%lf",&x,&y);
	}
}p[N],q[N];
bool cmp(Point a,Point b){
	if(a.x==b.x) return a.y<b.y; 
	return a.x<b.x;
}
bool cmps(Point a,Point b){
	return a.y<b.y;
}
double cdq(int l,int r){
	if(l==r) return 2e9;
	if(l+1==r) return p[l].dis(p[r]); 
	int mid = l+r>>1;
	double d = min(cdq(l,mid),cdq(mid+1,r));
	Point m = p[mid];
	int tot = 0;
	for(int i = l; i <= r; i++)
	if(fabs(p[i].x-p[mid].x)<=d) q[++tot]=p[i];
	sort(q+1,q+1+tot,cmps);
	for(int i = 1; i <= tot; i++)
	for(int j = i+1; j <= tot&& q[j].y-q[i].y<d; j++)
	d=min(d,q[j].dis(q[i])); 
	return d; 
}
int main(){
	while(scanf("%d",&n)&&n){
		for(int i = 1; i <= n; i++) p[i].input();
		sort(p+1,p+1+n,cmp);
		printf("%.2f\n",cdq(1,n));//输出最近距离 
	}
	return 0;
} 

// 
原创文章 85 获赞 103 访问量 2492

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/105729456