计算几何
准备
#include<bits/stdc++.h> using namespace std; const double eps=1e-6; int n,m; double x,y; struct point{//vector double x,y; };
基本运算
叉积
ab向量围成的平行四边形面积,如图红色部分
除以一边长后,为图形的高,即点线距
double len(point a){return sqrt(a.x*a.x+a.y*a.y);}//向量模 point operator+(point a,point b){return (point){a.x+b.x,a.y+b.y};} //点+向量=点 向量+向量=向量 point operator-(point a,point b){return (point){a.x-b.x,a.y-b.y};} //点-点=向量 向量-向量=向量 point operator*(point a,double k){return (point){a.x*k,a.y*k};}//数乘 double dc(point a,point b){return a.x*b.x+a.y*b.y;}//点乘 double operator*(point a,point b){return a.x*b.y-a.y*b.x;}//叉积
点线关系
点a关于直线b的对称点
point ref(point a,line b){ point vb=b.t-b.f;//用向量表示线 double dis=(b.f-a)*(b.t-a)/len(vb);//点线距 point dw={vb.y/len(vb),-vb.x/len(vb)};//单位向量旋转90 return a+(point){dw.x*2.0*dis,dw.y*2.0*dis}; }
左右关系
将点线转换成向量和向量,利用叉积正负判断向量的拐折关系
若(p2-p0)×(p1-p0)>0 p1p2由p1p0右拐得到,p0在p2p1左侧,向量p0p2在向量p0p1顺时针方向
若(p2-p0)×(p1-p0)<0 p1p2由p1p0左拐得到,p0在p2p1右侧,向量p0p2在向量p0p1逆时针方向
若(p2-p0)×(p1-p0)=0 p0p1p2共线
线线关系
直线交点
inline point cross(line a,line b){ point x=a.t-a.f,y=b.t-b.f,z=a.f-b.f; return a.f+x*(y*z/(x*y)); }
判断线段之间是否有交点(包括端点在另一线段上
inline int pan(line a,line b){ double c1=(a.t-a.f)*(b.f-a.f),c2=(a.t-a.f)*(b.t-a.f); double d1=(b.t-b.f)*(a.f-b.f),d2=(b.t-b.f)*(a.t-b.f); return c1*c2<=eps&&d1*d2<=eps; }
极角排序
在平面取一定点O,引出射线Ox为定轴,规定正方向顺/逆时针。以点到定点连线与定轴所成角为关键词排序
atan2
friend bool operator<(const point &a,const point &b){ return atan2(a.y,a.x)<atan2(b.y,b.x); }
atan2为tan反函数,值域-180~180
a为要求点A-定点O所得向量,即以O为坐标原点时A的坐标,y/x为tan即与x正半轴所成角
从小到大为从x负半轴逆时针到x负半轴,如图箭头方向
凸包
半平面交
应用:求给出向量左侧所围成凸包
1、极角排序 若两向量同向,只要最左侧向量OP
2、单调队列 同时压入向量,此向量和队列中上一向量交点(凸包预备点)
若队尾交点在加入向量外侧,弹出队尾向量和交点
进行到后面时,形成一个封闭图形,加入向量会对队头交点有影响,此时弹出队头
最后有一些无关向量,它们的左侧包含整个封闭图形,对答案没有限制作用。用队头向量弹出
放入队头和队尾交点后,交点队列(l,r]即为凸包点集
struct line{ point f,t; friend bool operator<(const line &a,const line &b){ double t1=atan2(a.t.y-a.f.y,a.t.x-a.f.x); double t2=atan2(b.t.y-b.f.y,b.t.x-b.f.x); if(fabs(t1-t2)>eps) return t1<t2; return (b.f-a.f)*(b.t-a.f)>eps; }friend bool operator!=(const line &a,const line &b){ double t1=atan2(a.t.y-a.f.y,a.t.x-a.f.x); double t2=atan2(b.t.y-b.f.y,b.t.x-b.f.x); return fabs(t1-t2)>eps; } } a[MAX],st[MAX];
sort(a+1,a+n+1); for(int i=1;i<=n;++i) if(a[i]!=a[i-1]){ while(r-l>1&&(a[i].t-t[r])*(a[i].f-t[r])>eps) --r; while(r-l>1&&(a[i].t-t[l+2])*(a[i].f-t[l+2])>eps) ++l; st[++r]=a[i]; if(r-l>1) t[r]=cross(st[r],st[r-1]); } while(r-l>1&&(st[l+1].t-t[r])*(st[l+1].f-t[r])>eps) --r; t[r+1]=cross(st[l+1],st[r]);++r;
动态凸包
up上凸包,down下凸包

#include<bits/stdc++.h> using namespace std; const double eps=1e-8; const double inf=1e10*1.0; #define IT set<point>::iterator int q,opt; double x,y; struct point{ double x,y; friend bool operator<(const point &a,const point &b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } }; double len(point a){return sqrt(a.x*a.x+a.y*a.y);} point operator+(point a,point b){return {a.x+b.x,a.y+b.y};} point operator-(point a,point b){return {a.x-b.x,a.y-b.y};} point operator*(point a,double k){return {a.x*k,a.y*k};} double dc(point a,point b){return a.x*b.x+a.y*b.y;} double operator*(point a,point b){return a.x*b.y-a.y*b.x;} struct ch{ int op;set<point>s; inline int PIP(point a){ IT it=s.lower_bound({a.x,-inf}); if(it==s.end()) return 0; if((*it).x==a.x) return (a.y-(*it).y)*op<=0; if(it==s.begin()) return 0; IT j=it;--j;return (a-*j)*(*it-*j)*op>=0; }inline int ju(IT it){ IT j=it,k=it; if(j--==s.begin()) return 0; if(++k==s.end()) return 0; return (*it-*j)*(*k-*j)*op>=0; }inline void in(point a){ if(PIP(a)) return; IT tmp=s.lower_bound({a.x,-inf}); if(tmp!=s.end()&&(*tmp).x==a.x) s.erase(tmp); s.insert(a);IT it=s.find(a),p=it; if(p--!=s.begin()) while(ju(p)) tmp=p--,s.erase(tmp); if(++it!=s.end()) while(ju(it)) tmp=it++,s.erase(tmp); } } up,down; int main(){ scanf("%d",&q);up.op=1;down.op=-1; while(q--){ scanf("%d%lf%lf",&opt,&x,&y); if(opt==1) up.in({x,y}),down.in({x,y}); else if(up.PIP({x,y})&&down.PIP({x,y})) printf("YES\n"); else printf("NO\n"); } }
面积
三角形直接套公式

inline double mian(point xa,point xb,point xc){ double a=len(xa-xb),b=len(xb-xc),c=len(xc-xa); double p=(a+b+c)*0.5; return sqrt(p*(p-a)*(p-b)*(p-c)); }
凸包在点集找一定点,依次取相邻两点,分成若干三角形
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律