在计算几何中,旋转卡壳算法(Rotating Calipers)是一种高效解决凸多边形相关问题的经典方法。它可以用于求解凸包的直径、宽度、最小面积外接矩形等问题。本教程将从零开始,用C语言带你一步步理解并实现这一算法,即使你是编程小白也能轻松上手!
想象你有一把卡尺(caliper),夹住一个凸多边形,然后慢慢旋转它。在旋转过程中,卡尺始终紧贴多边形的边界。通过这种方式,我们可以找到一些关键的几何特征,比如最远点对(即凸包直径)或最小外接矩形。
旋转卡壳的前提是已经有一个凸包(Convex Hull)。凸包可以理解为包裹所有点的最小凸多边形。我们可以使用 Graham 扫描法或 Andrew 算法先求出凸包。
下面是一个简单的 Andrew 算法实现(按 x 坐标排序,再构建上下凸壳):
// 点结构体typedef struct { double x, y;} Point;// 叉积:判断转向int cross(const Point &O, const Point &A, const Point &B) { return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);}// 比较函数:先按x,再按yint cmp(const void *a, const void *b) { Point *p1 = (Point *)a, *p2 = (Point *)b; if (p1->x == p2->x) return p1->y < p2->y ? -1 : 1; return p1->x < p2->x ? -1 : 1;}// 构建凸包int convex_hull(Point P[], int n, Point H[]) { if (n <= 1) return n; qsort(P, n, sizeof(Point), cmp); int k = 0; // 下凸壳 for (int i = 0; i < n; ++i) { while (k >= 2 && cross(H[k-2], H[k-1], P[i]) <= 0) k--; H[k++] = P[i]; } // 上凸壳 for (int i = n-2, t = k+1; i >= 0; --i) { while (k >= t && cross(H[k-2], H[k-1], P[i]) <= 0) k--; H[k++] = P[i]; } return k - 1; // 最后一点与第一点重复} 凸包直径是指凸包上任意两点之间的最大距离。暴力方法是 O(n²),而旋转卡壳可以在 O(n) 时间内完成。
核心思想:对于凸包上的每一条边,找到离它最远的点(对踵点)。随着边顺时针旋转,对踵点也单调移动,无需回溯。
#include <math.h>double dist(Point a, Point b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx*dx + dy*dy);}// 旋转卡壳求直径double rotating_calipers_diameter(Point H[], int m) { if (m == 1) return 0; if (m == 2) return dist(H[0], H[1]); double max_dist = 0; int j = 1; // 对踵点索引 for (int i = 0; i < m; i++) { // 找到使三角形面积最大的 j while (cross(H[i], H[(i+1)%m], H[(j+1)%m]) > cross(H[i], H[(i+1)%m], H[j])) { j = (j + 1) % m; } // 更新最大距离 max_dist = fmax(max_dist, dist(H[i], H[j])); max_dist = fmax(max_dist, dist(H[(i+1)%m], H[j])); } return max_dist;} 这个名字来源于其几何直观:就像用两把平行的卡尺夹住凸多边形,一边旋转一边保持接触。在 C 语言实现中,我们通过叉积判断“高度”变化,从而模拟这一旋转过程。
通过本教程,你应该已经掌握了旋转卡壳的基本原理和 C 语言实现。记住,关键在于理解叉积如何帮助我们判断“最远点”,以及为什么对踵点可以单调移动。
继续练习吧!尝试用这个算法解决实际问题,比如在地图上找两个最远的城市,或者为机器人路径生成最小包围区域。
本文由主机测评网于2025-12-03发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025122346.html