计算几何题目总结
模板 (只用这一个) 点 线 圆
//#include<bits/stdc++.h> #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #include <map> #include <vector> #include <set> #include <string> #include <math.h> using namespace std; const double eps=1e-8; const double pi=acos(-1.0); inline double sqr(double x){ return x*x; } inline int dcmp(double x) { if(fabs(x)<eps) return 0;return (x>0? 1: -1);} struct Point{ double x,y; Point(){ x=0,y=0; } Point(double _x,double _y):x(_x),y(_y){} void input(){ scanf("%lf%lf",&x,&y); } void output(){ printf("%.2f %.2f ",x,y); } friend istream &operator >>(istream &os,Point &b){os>>b.x>>b.y;return os; } friend ostream &operator <<(ostream &os,Point &b){os<<b.x<<' '<<b.y;return os; } bool operator ==(const Point &b)const{return ( dcmp(x-b.x)==0&&dcmp(y-b.y)==0); } bool operator !=(const Point &b)const{return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0)); } bool operator <(const Point &b)const {return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x); } double operator ^(const Point &b)const{ return x*b.y-y*b.x;}//叉积 double operator *(const Point &b)const{ return x*b.x+y*b.y;} //点积 Point operator +(const Point &b)const { return Point(x+b.x,y+b.y);} Point operator -(const Point &b)const { return Point(x-b.x,y-b.y);} Point operator *(double a) { return Point(x*a,y*a); } Point operator /(double a) { return Point(x/a,y/a); } double len2() { return sqr(x)+sqr(y); }//长度平方 double len() { return sqrt(len2()); }//长度 double polar(){ return atan2(y,x); }//向量的极角 //返回与x轴正向夹角(-pi~pi] Point change_len(double r){ //转化为长度为r的向量 double l=len(); if(dcmp(l)==0) return *this; //零向量 return Point(x*r/l,y*r/l); } Point rotate_left() { return Point(-y,x); }//逆时针旋转90度 Point rotate_right(){ return Point(y,-x); }//顺时针旋转90度 Point rotate(Point p,double ang){ //绕点p逆时针旋转ang度 Point v=(*this)-p; double c=cos(ang),s=sin(ang); return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c); } Point normal(){ return Point(-y/len(),x/len()); }//单位化,逆时针旋转90° }; inline double cross(Point a,Point b) { return a.x*b.y-a.y*b.x; } //叉积 inline double dot(Point a,Point b) { return a.x*b.x+a.y*b.y; } //点积 double rad(Point a,Point b) { return fabs(atan2(fabs(cross(a,b)),dot(a,b))); } //两个向量的夹角 double area2(Point A, Point B, Point C) { return cross(B-A, C-A); } // 四边形面积 bool is_parallel(Point a,Point b) { double p=rad(a,b);return dcmp(p)==0||dcmp(p-pi)==0; }//判断向量是否平行 typedef Point Vector; double Angle(Vector A, Vector B) { return acos(dot(A, B)/A.len()/B.len()); } // 角度 double dis(Point A,Point B) { return sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));} Vector Normal(Vector A) { double L =A.len(); return Vector(-A.y/L, A.x/L); } //rad为弧度 且为逆时针旋转的角 bool ToLeftTest(Point a,Point b,Point c){ return cross(b - a, c - b) > 0; } //向量A左转90°的单位法向量 struct Line{ Point s,e; Line(){} Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线 Line(Point p,double ang){ //一个点和斜率(弧度制)确定直线 s=p; if(dcmp(ang-pi/2)==0){ e=s+Point(0,1); } else { e=s+Point(1,tan(ang)); } } void input(){ s.input(); e.input(); } Point operator &(const Line &b)const{ //求两直线交点 Point res=s; double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e)); res.x+=(e.x-s.x)*t; res.y+=(e.y-s.y)*t; return res; } }; struct Circle{ Point c; double r; Circle() {c.x=0; c.y=0; r=0; } Circle(Point c,double r):c(c),r(r) {} Point point(double a){ return Point (c.x+cos(a)*r,c.y+sin(a)*r); } }A,B; Point Circle_Cirle(Circle c1, Circle c2){ double d=dis(c1.c,c2.c); Point k=c2.c-c1.c; double a=k.polar(); double da=acos( (c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d) ); Point p1=c1.point(a-da); //printf("%.10f %.10f ",p1.x,p1.y); Point p2=c1.point(a+da); // printf("%.10f %.10f ",p2.x,p2.y) return p1; } double PolygonArea(vector<Point> p){ //多边形的有向面积,加上绝对值就是面积 正值表示输入点按照逆时针 否则为顺时针 int n=p.size(); double area=0; for(int i=1;i<n-1;i++) area+=cross(p[i]-p[0],p[i+1]-p[0]); return fabs(area/2); // 可改 } double PolygonLength(vector<Point> vp){ //多边形周长 int m=vp.size(); double area=0; for(int i=0;i<m;i++) area+=dis(vp[i],vp[(i+1)%m]); return fabs(area/2); } bool up(Point a,Point b) { if(a.x!=b.x) return a.x<b.x; return a.y<b.y; } bool cmp2(Point a,Point b){ Point c; return cross(a-c,b-c)>0; } bool cmp1(Point a,Point b) // (-pi,pi] { if( abs(atan2(a.y,a.x)-atan2(b.y,b.x))>eps ) return atan2(a.y,a.x)<atan2(b.y,b.x); else return a.x<b.x; } int Quadrant(Point a)//象限排序,注意包含四个坐标轴 { if(a.x>0&&a.y>=0) return 1; if(a.x<=0&&a.y>0) return 2; if(a.x<0&&a.y<=0) return 3; if(a.x>=0&&a.y<0) return 4; } bool cmp3(Point a,Point b) //先按象限从小到大排序 再按极角从小到大排序 { if(Quadrant(a)==Quadrant(b))//返回值就是象限 return cmp1(a,b); else Quadrant(a)<Quadrant(b); } bool cmp(Point a, Point b)//先按象限排序,再按极角排序,再按远近排序 { if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x; if (a.y == 0 && a.x >= 0 && b.y != 0)return true; if (b.y == 0 && b.x >= 0 && a.y != 0)return false; if (b.y*a.y <= 0)return a.y>b.y; Point one; one.y = one.x = 0; return cross(one-a,one-b) > 0 || (cross(one-a,one-b) == 0 && a.x < b.x); } void tubao(vector<Point> vs){ Point pa[60]; Point pt[60]; int n=vs.size(); for(int i=0;i<n;i++) pa[i]=vs[i]; sort(pa,pa+n,up); int m=0; for(int i=0;i<n;i++) { while(m>1 && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--; pt[m++]=pa[i]; } int k=m; for(int i=n-2;i>=0;i--) { while(m>k && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--; pt[m++]=pa[i]; } if(n>1) m--; // 1-m } const int maxn=60; Point pa[maxn]; int main(){ Point s; scanf("%lf %lf",&s.x,&s.y); int tot=1; while(~scanf("%lf %lf",&pa[tot].x,&pa[tot].y) && pa[tot].x!=1100) {++tot; } //cout<<tot<<endl; sort(pa+1,pa+tot,cmp2); printf("(%.0f,%.0f) ",s.x,s.y); for(int i=1;i<tot;i++){ printf("(%.0f,%.0f) ",pa[i].x,pa[i].y); } }
平面直线图 ( 求直线交的多边形第K大模板 )
struct PSLG{ //平面直线图 处理平面内所有直线围成的所有多边形 传入直线交点之间的每条线段 struct Edge{ int from,to; double ang; Edge(){ ang=from=to=0; } Edge(int s,int t,double a){ from=s,to=t,ang=a; } }; int n,m,face_cnt; //平面个数 包括外面最大的多边形 double area[MAXN]; //每个多边形面积 Point point[MAXN]; //平面内所有的点 vector<Edge>edge; vector<int>G[MAXN]; vector<vector<Point> >face; int vis[2*MAXN],left[2*MAXN],pre[2*MAXN]; //left表示这条边的左侧属于哪个面 void Init(){ face.clear(); edge.clear(); for(int i=0;i<n;i++) G[i].clear(); n=m=0; } PSLG(){ Init(); } void AddEdge(int from, int to){ //需要建立反向边帮助寻找下一条边 edge.pb(Edge(from,to,(point[to]-point[from]).polar())); edge.pb(Edge(to,from,(point[from]-point[to]).polar())); m=edge.size(); G[from].pb(m-2); G[to].pb(m-1); } void Build(){ for(int u=0;u<n;u++){ int d=G[u].size(); for(int i=0;i<d;i++) for(int j=i+1;j<d;j++) if(edge[G[u][i]].ang>edge[G[u][j]].ang) swap(G[u][i],G[u][j]); for(int i=0;i<d;i++) pre[G[u][(i+1)%d]]=G[u][i]; //从u出发的i条边顺时针旋转的第一条边是pre[i] } face_cnt=0; memset(vis,0,sizeof(vis)); for(int u=0;u<n;u++){ for(int i=0;i<G[u].size();i++){ int e=G[u][i]; if(!vis[e]){ face_cnt++; vector<Point> polygon; while(1){ vis[e]=1; left[e]=face_cnt; int from=edge[e].from; polygon.pb(point[from]); e=pre[e^1]; //逆时针旋转最多的一条边即为顺时针转动的第一条边 if(e==G[u][i]) break; } face.pb(polygon); } } } for(int i=0;i<face_cnt;i++) area[i]=polygon_area(face[i]); /* 包括外面最大的 int n; scanf("%d",&n); for(int i=0;i<n;i++) line[i].input(); for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++) if(!is_parallel(line[i].e-line[i].s,line[j].e-line[j].s)){ Point inter=line[i]&line[j]; pslg.point[pslg.n++]=inter; point[i].pb({dot(inter-line[i].s,line[i].e-line[i].s),pslg.n-1}); point[j].pb({dot(inter-line[j].s,line[j].e-line[j].s),pslg.n-1}); } sort(point[i].begin(),point[i].end()); for(int j=1;j<point[i].size();j++) pslg.AddEdge(point[i][j-1].se,point[i][j].se); } */ } };