📅  最后修改于: 2023-12-03 15:12:18.449000             🧑  作者: Mango
在计算几何中,边数最少的多边形指的是边数最少的可以将给定一组点覆盖的多边形。这个问题又称作最小凸包问题。
在计算几何中,凸包指的是包含给定点集的最小凸多边形。凸多边形是对于任意两个点,连线在多边形内的多边形。凸包可以用来解决很多计算几何问题,例如最近点对问题和内部点问题。
计算凸包有多种方法,包括朴素算法、Graham扫描算法和Jarvis步进算法。最小凸包问题一般使用Graham扫描算法来解决。
在Graham扫描算法中,我们首先找到给定点集中的最低点,然后按照相对于该点的极角对其余点进行排序。然后,我们遍历排序后的点,将它们加入凸包中,保证加入每个新点后凸包仍然是凸的。
这个算法的复杂度为O(nlogn),其中n为点数。
最小凸包的边数等于点集中的点数,因此,在任何情况下,边数最少的多边形都具有n条边。
这里提供C++代码实现最小凸包的Graham扫描算法:
// 二维向量
struct Vector2D {
double x, y;
Vector2D(double a = 0, double b = 0) : x(a), y(b){}
Vector2D operator + (const Vector2D &v) const {
return Vector2D(x + v.x, y + v.y);
}
Vector2D operator - (const Vector2D &v) const {
return Vector2D(x - v.x, y - v.y);
}
Vector2D operator * (double d) const {
return Vector2D(x * d, y * d);
}
double cross(const Vector2D &v) const {
return x * v.y - y * v.x;
}
bool operator < (const Vector2D& v) const {
return x < v.x || (x == v.x && y < v.y);
}
};
// 判断三个点的排列关系
double cross(Vector2D A, Vector2D B, Vector2D C) {
Vector2D AB = B - A;
Vector2D AC = C - A;
return AB.cross(AC);
}
// Graham扫描算法
vector<Vector2D> convexHull(vector<Vector2D> points) {
int n = points.size();
sort(points.begin(), points.end());
int k = 0;
vector<Vector2D> hull(n * 2);
for(int i = 0; i < n; i++) {
while(k >= 2 && cross(hull[k - 2], hull[k - 1], points[i]) <= 0) k--;
hull[k++] = points[i];
}
for(int i = n - 2, t = k + 1; i >= 0; i--) {
while(k >= t && cross(hull[k - 2], hull[k - 1], points[i]) <= 0) k--;
hull[k++] = points[i];
}
hull.resize(k - 1);
return hull;
}
返回的凸包点集便是可以覆盖原始点集的最小凸多边形。