OI+ACM 笔记:G - 计算几何

G - 计算几何

计算几何基础

精度

误差量:通常来说,若问题要求精确到小数点后 \(\alpha\) 位,则误差量 \(\epsilon = 10^{-(\alpha + 2)}\)

const double eps = 1e-...;

符号函数

int sgn(double x) {
	if (fabs(x) < eps) return 0;
	return x > 0 ? 1 : -1;
}

比较函数

int dcmp(double x, double y) { return sgn(x - y); }

点、向量

点、向量的结构体声明

struct point {
	double x, y;
    point() { x = y = 0; }
	point(double A, double B) : x(A), y(B) {}
};

typedef point vec;

// vector addition, subtraction and multiplication.
vec operator + (vec a, vec b) { return vec(a.x + b.x, a.y + b.y); }
vec operator - (vec a, vec b) { return vec(a.x - b.x, a.y - b.y); }
vec operator * (vec a, double b) { return vec(a.x * b, a.y * b); }

// dot product.
double dot(vec a, vec b) {
	return a.x * b.x + a.y * b.y;
}

// cross product.
double cross(vec a, vec b) {
	return a.x * b.y - b.x * a.y;
}

// vector length.
double get_length(vec a) { return sqrt(dot(a, a)); }

// vector angle.
double get_angle(vec a, vec b) { return acos(dot(a, b) / get_length(a) / get_length(b)); }

// vector anticlockwise rotate.
vec rotate(vec a, double angle) {
	double x = a.x * cos(angle) - a.y * sin(angle);
	double y = a.x * sin(angle) + a.y * cos(angle);
	return vec(x, y);
}

点积\(\vec{a}\)\(\vec{b}\) 的点积,为 \(\vec{a}\)\(\vec{b}\) 上的投影与 \(\vec{b}\) 的模长的积,易证该点积也为 \(\vec{b}\)\(\vec{a}\) 上的投影与 \(\vec{a}\) 的模长的积。

\[\begin{aligned} \vec{a} \cdot \vec{b} & = |\vec{a}||\vec{b}| \cos \langle \vec{a}, \vec{b} \rangle \\ & = x_ax_b + y_ay_b \end{aligned} \]

叉积\(\vec{a}\)\(\vec{b}\) 的叉积,为 \(\vec{a}\)\(\vec{b}\) 围成的平行四边形的有向面积(以 \(\vec{a}\) 为基准,逆时针为正、顺时针为负)。

\[\begin{aligned} \vec{a} \times \vec{b} & = |\vec{a}||\vec{b}| \sin \langle \vec{a}, \vec{b} \rangle \\ & = x_ay_b - y_ax_b \end{aligned} \]

直线

直线表示法:可用一对互不相同的点确定一条直线,也可以用直线上一点和直线上的方向向量确定一条直线。

直线 \(p + x \cdot t\)\(q + y \cdot t\) 求交

point line_intersection(point p, vec x, point q, vec y) {
	vec u = q - p;
	double t = cross(u, y) / cross(x, y);
	return p + x * t;
}

\(p\) 到直线 \(AB\) 的距离

double distance_line(point p, point a, point b) {
	vec u = b - a, v = p - a;
	return fabs(cross(u, v)) / get_length(u);
}

\(p\) 到线段 \(AB\) 的距离

double distance_seg(point p, point a, point b) {
	if (a == b) return get_length(p - a);
	vec u = b - a, va = p - a, vb = p - b;
	if (sgn(dot(u, va)) < 0) return get_length(va);
	if (sgn(dot(u, vb)) > 0) return get_length(vb);
	return distance_line(p, a, b);
}

\(p\) 在直线 \(AB\) 上的投影(垂线段的垂足)

double line_projection(point p, point a, point b) {
	vec u = b - a, v = p - a;
	return a + u * (dot(u, v) / dot(u, u));
}

\(p\) 是否在线段 \(AB\)

bool on_seg(point p, point a, point b) {
	vec u = p - a, v = p - b;
	return !sgn(cross(u, v)) && sgn(dot(u, v)) <= 0;
}

线段 \(AB\)\(CD\) 是否有交点(跨立实验)

bool seg_intersection(point Xa, point Xb, point Ya, point Yb) {
	int X = 1, Y = 1;
	X *= sgn(cross(Xb - Xa, Ya - Xa));
	X *= sgn(cross(Xb - Xa, Yb - Xa));
	Y *= sgn(cross(Yb - Ya, Xa - Ya));
	Y *= sgn(cross(Yb - Ya, Xb - Ya));
	return X <= 0 && Y <= 0;
}

应用

三角形面积(坐标)

double area(point a, point b, point c) {
	return fabs(cross(b - a, c - a)) / 2;
}

三角形面积(边长)

double area(double a, double b, double c) {
	double p = (a + b + c) / 2;
	return sqrt(p * (p - a) * (p - b) * (p - c));
}

多边形面积:不一定要凸多边形,但要保证多边形的顶点按顺时针或逆时针的顺序给出。

double polygon_area(int n, point p[]) {
	double sum = 0;	
	for (int i = 2; i < n; i ++) sum += cross(p[i] - p[1], p[i + 1] - p[i]);
	return fabs(ans / 2);
}

凸包

  • \(n \times n\) 的整点网格中,最大凸包的大小为 \(\mathcal{O}(n^{\frac{2}{3}})\) 级别。
posted @ 2022-12-19 10:23  Calculatelove  阅读(191)  评论(0编辑  收藏  举报