旋转卡壳法 最小外接矩形

时间: 2023-10-09 12:10:55 浏览: 66
旋转卡壳法是一种计算几何的算法,用于求解平面上点集的最大直径、最远点对、最小包围圆以及最小包围矩形等问题。其中,最小包围矩形也称作最小外接矩形,是指能够包围所有点的面积最小的矩形。 在旋转卡壳法中,我们首先找到点集中的最左侧、最右侧、最上方和最下方的点,然后将它们两两配对,形成四条初始的平行于坐标轴的边界线段。接着,我们绕着其中一条边界线段,依次计算所有点到该线段的垂线距离,并记录距离最大的点。然后,我们将该点和该线段的下一个相邻线段配对,形成新的边界线段。如此重复,直到回到起点,此时就可以求得最小包围矩形。 需要注意的是,在求解最小包围矩形时,需要考虑点集的凸包。因为凸包上的点可以唯一确定最小包围矩形。如果点集不是凸包,则需要先求出凸包,然后再进行计算。 总的来说,旋转卡壳法是一种非常高效的算法,可以在O(n)的时间复杂度内解决最小包围矩形问题。
相关问题

旋转卡壳最小外接矩形 C++代码

以下是旋转卡壳求最小外接矩形的C++代码: ```c++ #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 100005; const double eps = 1e-8; const double pi = acos(-1.0); struct Point { double x, y; Point() {} Point(double x, double y): x(x), y(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 p) { return Point(a.x * p, a.y * p); } Point operator / (Point a, double p) { return Point(a.x / p, a.y / p); } double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; } double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; } double Length(Point a) { return sqrt(Dot(a, a)); } double Angle(Point a, Point b) { return acos(Dot(a, b) / Length(a) / Length(b)); } bool cmp(Point a, Point b) { if (a.x != b.x) return a.x < b.x; return a.y < b.y; } int n; Point p[MAXN], ch[MAXN], u[MAXN], v[MAXN]; void Andrew() { sort(p, p + n, cmp); int m = 0; for (int i = 0; i < n; i++) { while (m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) < 0) m--; ch[m++] = p[i]; } int k = m; for (int i = n - 2; i >= 0; i--) { while (m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) < 0) m--; ch[m++] = p[i]; } if (n > 1) m--; ch[m] = ch[0]; } double RotatingCalipers() { double ans = 1e18; int j = 1, k = 1, l = 1; for (int i = 0; i < n; i++) { while (fabs(Cross(ch[i + 1] - ch[i], ch[j + 1] - ch[i])) > fabs(Cross(ch[i + 1] - ch[i], ch[j] - ch[i]))) j = (j + 1) % n; while (fabs(Dot(ch[i + 1] - ch[i], ch[k + 1] - ch[i])) > fabs(Dot(ch[i + 1] - ch[i], ch[k] - ch[i]))) k = (k + 1) % n; if (i == 0) l = k; while (fabs(Dot(ch[i + 1] - ch[i], ch[l + 1] - ch[i])) > fabs(Dot(ch[i + 1] - ch[i], ch[l] - ch[i]))) l = (l + 1) % n; Point u = ch[j] - ch[i], v = ch[k] - ch[i], w = ch[l] - ch[i]; double angle = Angle(u, v); double len = Length(u); double h = fabs(Cross(u, w)) / len; double w1 = len * sin(angle), w2 = sqrt(Length(v) * Length(v) - h * h); ans = min(ans, w1 * w2); } return ans; } int main() { cin >> n; for (int i = 0; i < n; i++) { cin >> p[i].x >> p[i].y; } Andrew(); double ans = RotatingCalipers(); printf("%.2lf\n", ans); return 0; } ``` 其中 `Andrew()` 函数是求凸包的函数,`RotatingCalipers()` 函数是旋转卡壳求最小外接矩形的函数。

旋转卡壳最小外接矩形 C++代码加注释

旋转卡壳(Rotating Calipers)算法用于求解凸包的最小外接矩形(Minimum Bounding Rectangle)。下面是C++实现代码,带有注释说明: ```cpp #include <bits/stdc++.h> using namespace std; const int N = 100010; // 点数的最大值 struct Point { double x, y; Point() {} Point(double x, double y) : x(x), y(y) {} Point operator - (const Point& p) const { return Point(x - p.x, y - p.y); } }; int n; // 输入点数 Point p[N]; // 输入点 // 计算叉积 (P1-P0)x(P2-P0) double cross(const Point& p1, const Point& p2, const Point& p0) { return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); } // 计算距离的平方 double dis2(const Point& A, const Point& B) { return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y); } // 旋转卡壳 double rotating_calipers(Point* p, int n) { double ans = 1e18; // 最小面积 int j = 2; // 第二个点 for (int i = 1; i <= n; i++) { // 以 p[i] 为起点,旋转卡壳 while (cross(p[i + 1], p[j + 1], p[i]) > cross(p[i + 1], p[j], p[i])) { j = j % n + 1; // 旋转 } ans = min(ans, dis2(p[i], p[j])); // 更新答案 } return ans; } int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> p[i].x >> p[i].y; } sort(p + 1, p + n + 1, [](Point a, Point b) { if (a.x != b.x) return a.x < b.x; return a.y < b.y; }); // 按 x 从小到大排序 double ans = rotating_calipers(p, n); printf("%.2lf\n", sqrt(ans)); // 输出最小面积的平方根 return 0; } ``` 注释中已经详细解释了每一段代码的含义,这里再简单介绍一下旋转卡壳的思路: 1. 将所有点按 x 坐标从小到大排序,取最左边的点 p1; 2. 以 p1 为起点,找到与其构成的向量中,与 y 轴平行的向量(即最上方的向量); 3. 以这个向量的终点作为起点,继续找到与其构成的向量中,与 x 轴平行的向量(即最右边的向量); 4. 以这个向量的终点作为起点,继续找到与其构成的向量中,与 y 轴相反的向量(即最下方的向量); 5. 以这个向量的终点作为起点,继续找到与其构成的向量中,与 x 轴相反的向量(即最左边的向量); 6. 回到起点 p1,以此为起点,继续以上的操作,直到找到最小的外接矩形。 其中,每次找到一个向量,可以通过计算叉积的符号来判断向量是否满足要求。

相关推荐

最新推荐

recommend-type

最小圆覆盖 半平面交 凸包 三维几何

最小圆覆盖 半平面交 凸包 Pick公式多边形内整点个数 这个平面多边形的重心 三维几何库 旋转卡壳求最近点对
recommend-type

pre_o_1csdn63m9a1bs0e1rr51niuu33e.a

pre_o_1csdn63m9a1bs0e1rr51niuu33e.a
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

SPDK_NVMF_DISCOVERY_NQN是什么 有什么作用

SPDK_NVMF_DISCOVERY_NQN 是 SPDK (Storage Performance Development Kit) 中用于查询 NVMf (Non-Volatile Memory express over Fabrics) 存储设备名称的协议。NVMf 是一种基于网络的存储协议,可用于连接远程非易失性内存存储器。 SPDK_NVMF_DISCOVERY_NQN 的作用是让存储应用程序能够通过 SPDK 查询 NVMf 存储设备的名称,以便能够访问这些存储设备。通过查询 NVMf 存储设备名称,存储应用程序可以获取必要的信息,例如存储设备的IP地址、端口号、名称等,以便能
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。
recommend-type

"互动学习:行动中的多样性与论文攻读经历"

多样性她- 事实上SCI NCES你的时间表ECOLEDO C Tora SC和NCESPOUR l’Ingén学习互动,互动学习以行动为中心的强化学习学会互动,互动学习,以行动为中心的强化学习计算机科学博士论文于2021年9月28日在Villeneuve d'Asq公开支持马修·瑟林评审团主席法布里斯·勒菲弗尔阿维尼翁大学教授论文指导奥利维尔·皮耶昆谷歌研究教授:智囊团论文联合主任菲利普·普雷教授,大学。里尔/CRISTAL/因里亚报告员奥利维耶·西格德索邦大学报告员卢多维奇·德诺耶教授,Facebook /索邦大学审查员越南圣迈IMT Atlantic高级讲师邀请弗洛里安·斯特鲁布博士,Deepmind对于那些及时看到自己错误的人...3谢谢你首先,我要感谢我的两位博士生导师Olivier和Philippe。奥利维尔,"站在巨人的肩膀上"这句话对你来说完全有意义了。从科学上讲,你知道在这篇论文的(许多)错误中,你是我可以依
recommend-type

实现实时监控告警系统:Kafka与Grafana整合

![实现实时监控告警系统:Kafka与Grafana整合](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy9BVldpY3ladXVDbEZpY1pLWmw2bUVaWXFUcEdLT1VDdkxRSmQxZXB5R1lxaWNlUjA2c0hFek5Qc3FyRktudFF1VDMxQVl3QTRXV2lhSWFRMEFRc0I1cW1ZOGcvNjQw?x-oss-process=image/format,png) # 1.1 Kafka集群架构 Kafka集群由多个称为代理的服务器组成,这
recommend-type

Windows 运行Python脚本

要在 Windows 上运行 Python 脚本,你需要先安装 Python。可以从官网下载 Python 安装包并按照提示进行安装。安装完成后,就可以在命令行中输入 `python` 命令,进入 Python 解释器环境。 接着,你可以编写 Python 脚本,保存为 `.py` 后缀的文件。在命令行中进入脚本所在的目录,输入 `python script.py` 命令来运行脚本。其中 `script.py` 是你的脚本文件名。 如果你想在 Windows 上运行一个 Python 程序,但不想打开命令行窗口,可以将脚本文件拖动到 Python 可执行文件 `python.exe` 上,