计算几何模板
全是纯干货,方法理解可查阅算法入门到进阶一书 !
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double INF = 1e20;
const double pi = acos(-1.0);//高精度圆周率
const double eps = 1e-8;//偏差值
const int maxn = 1010;//点的数量
//判断是否等于零,返回0为等于零,返回-1为小于,1为大于
int sgn(double x) {
if (fabs(x) < eps)return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(Point B) { return Point(x + B.x, y + B.y); }
Point operator-(Point B) { return Point(x - B.x, y - B.y); }
Point operator*(double k) { return Point(x * k, y * k); }//放大k倍
Point operator/(double k) { return Point(x / k, y / k); }//缩小k倍
bool operator==(Point B) { return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; }
bool operator<(Point B) {return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0); }//用于对顶点的排序
friend bool operator < (Point a,Point b){
return sgn(a.x - b.x) < 0 || (sgn(a.x - b.x) == 0 && sgn(a.y - b.y) < 0);
}
};
bool cmpxy(Point A,Point B){ //先对x排序再对y排序
return sgn(A.x - B.x) < 0 || (sgn(A.x - B.x) == 0 && sgn(A.y - B.y) < 0);
}
bool cmpy(Point A, Point B) { return sgn(A.y - B.y) < 0; } //只对y坐标排序
typedef Point Vector;
//向量叉积;大于0,B在A逆时针方向;等于0,A、B重合
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x;}
//两点距离
double Distance(Point A, Point B) { return hypot(A.x - B.x, A.y - B.y);}
// 半平面交
struct Line{
Point p; //直线上一个点
Vector v; //方向向量,左边是半平面
double ang; //极角,从x正半轴旋转到v的角度
Line(){};
Line(Point p,Vector v):p(p),v(v){ang = atan2(v.y,v.x);}
friend bool operator < (Line a,Line b){return a.ang < b.ang;}//用于排序
};
// p在线L的左边
bool OnLeft(Line L,Point p){return sgn(Cross(L.v,p - L.p )) > 0;}
Point Cross_point(Line a,Line b){ //两直线的交点
Vector u = a.p - b.p;
double t = Cross(b.v, u) / Cross(a.v, b.v);
return a.p + a.v * t;
}
vector<Point> HPI(vector<Line> L){
int n=L.size();
sort(L.begin(),L.end());//将所有半平面按照极角排序。
int first,last;
vector<Point> p(n);
vector<Line> q(n);
vector<Point> ans;
q[first=last=0]=L[0];
for(int i=1;i<n;i++){
while(first<last&&!OnLeft(L[i],p[last-1]))last--;//删除顶部的半平面
while(first<last&&!OnLeft(L[i],p[first]))first++;//删除底部的半平面
q[++last]=L[i];//将当前的半平面假如双端队列顶部。
if(fabs(Cross(q[last].v,q[last-1].v))<eps){//对于极角相同的,选择性保留一个。
last--;
if(OnLeft(q[last],L[i].p))q[last]=L[i];
}
if(first<last)p[last-1]=Cross_point(q[last-1],q[last]);//计算队列顶部半平面交点。
}
while(first<last&&!OnLeft(q[first],p[last-1]))last--;//删除队列顶部的无用半平面。
if(last-first<=1)return ans;//半平面退化
p[last]=Cross_point(q[last],q[first]);//计算队列顶部与首部的交点。
for(int i=first;i<=last;i++)ans.push_back(p[i]);//将队列中的点复制。
return ans;
}
//最近点对
Point p[maxn], tmp_p[maxn];
double Closest_Pair(int left,int right){
double dis = INF;
if(left == right) return dis; //只剩一个点
if(left + 1 == right) //只剩两个点
return Distance(p[left], p[right]);
int mid = (left + right) / 2; //分治
double d1 = Closest_Pair(left, mid); //求S1内的最近点对
double d2 = Closest_Pair(mid + 1, right); //求S2内的最近点对
dis = min(d1, d2);
int k = 0;
for (int i = left; i <= right;i ++){ //在s1和s2中间附近找可能的最小点对
if(fabs(p[mid].x - p[i].x) <= dis) //按x坐标来找
tmp_p[k++] = p[i];
}
sort(tmp_p, tmp_p + k, cmpy); //按照y坐标进行排序
for (int i = 0; i < k;i ++){
for (int j = i + 1; j < k;j ++){
if(tmp_p[j].y - tmp_p[i].y >= dis) break;
dis = min(dis, Distance(tmp_p[i], tmp_p[j]));
}
}
return dis;
}
//
int main() {
//ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
return 0;
}