我的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;
} 

// 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值