当前位置: 首页 > news >正文

二维凸包算法 Julia实现

问题描述:给定平面上 n n n 个点的集合 Q Q Q,求其子集 P P P 构成 Q Q Q 的凸包,即 ∀ p ∈ Q , ∃ p 0 , p 1 , p 2 ∈ P \forall p \in Q, \exist p_0, p_1, p_2 \in P pQ,p0,p1,p2P 使得点 p p p 在以点 p 0 , p 1 , p 2 p_0, p_1, p_2 p0,p1,p2 构成的三角形中或边上。

朴素枚举

初始设 P : = Q P := Q P:=Q,枚举 p 0 , p 1 , p 2 , p p_0, p_1, p_2, p p0,p1,p2,p,判断 p p p 是否在以点 p 0 , p 1 , p 2 p_0, p_1, p_2 p0,p1,p2 构成的三角形中,是则删去 p p p,最后剩下的即为凸包。注意到纵坐标最小的点必在结果中,可将 p 0 p_0 p0 固定为之。

算法时间复杂度 O ( n 3 ) O(n^3) O(n3)。代码:

cross(p, q) = p[1] * q[2] - q[1] * p[2]function NE(Q)function inΔ(p0, p1, p2, p)v0, v1, v2 = p .- p0, p1 .- p0, p2 .- p0c0, c1, c2 = cross(v1, v2), cross(v0, v1), cross(v0, v2)return c0 * c1 < 0 && c0 * c2 > 0 && abs(c2 - c1) < abs(c0)endm = argmin(last.(Q))p0, Q = Q[m], vcat(Q[begin : m - 1], Q[m + 1 : end])for i = length(Q) : -1 : 1f = falsefor j = 2 : length(Q)if i == j continue endfor k = 1 : j - 1if i == k continue endif inΔ(p0, Q[j], Q[k], Q[i])f = true; breakendendif f break endendif fdeleteat!(Q, i)endendsort!(Q, lt = (p, q) -> cross(p .- p0, q .- p0) > 0)return vcat(p0, Q)
end

Jarvis March 算法

按逆时针对 P P P 排序,将问题转化成已知 p 0 , p 1 , . . . , p k p_0, p_1, ..., p_k p0,p1,...,pk 如何求 p k + 1 p_{k+1} pk+1

p 0 p_0 p0 固定为纵坐标最小的点。此时 Q − { p k } Q - \{p_k\} Q{pk} 中所有点都在向量 p k − p k − 1 p_k - p_{k-1} pkpk1 的左侧,即向量集 { p − p k ∣ p ∈ Q − { p k } } \{ p - p_k | p \in Q - \{ p_k \} \} {ppkpQ{pk}} 可在叉积运算的正负性上构成偏序集,最右的向量即为 p k + 1 − p k p_{k+1} - p_k pk+1pk。当 p k + 1 = p 0 p_{k+1} = p_0 pk+1=p0 时算法终止。

时间复杂度 O ( n h ) O(nh) O(nh) h h h 为凸包的点数。代码:

function Jarvis(Q)function march(A, cmp)r = A[begin]for i in A[2 : end]if cmp(i, r)r = iendendreturn rendP = [march(Q, (p, q) -> last(p) < last(q))]while trueq = march(Q, (p, q) -> cross(p .- P[end], q .- P[end]) > 0)if P[begin] == qbreakendpush!(P, q)endreturn P
end

Graham Scan 算法

p 0 p_0 p0 固定为纵坐标最小的点。按与 p 0 p_0 p0 构成向量的极角序对 Q Q Q 排序,将问题转化为已知 Q Q Q 中前 k k k 个点的闭包 P k P_k Pk,如何求 Q Q Q 中前 k + 1 k + 1 k+1 个点的闭包 P k + 1 P_{k+1} Pk+1

不妨设 P k = { p 0 , p 1 , . . , p k } P_k = \{ p_0, p_1, .., p_k \} Pk={p0,p1,..,pk},注意到 p k + 1 p_{k+1} pk+1 的在 p k − p 0 p_k - p_0 pkp0 的左边,而 P k P_k Pk 中其它点在 p k − p 0 p_k - p_0 pkp0 的右边,故一定有 p k + 1 ∈ P k + 1 p_{k+1} \in P_{k+1} pk+1Pk+1,设 P k + 1 = P k + { p k + 1 } P_{k+1} = P_k + \{ p_{k+1} \} Pk+1=Pk+{pk+1}。判断 p k + 1 p_{k+1} pk+1 p k − p k − 1 p_k - p_{k-1} pkpk1 的哪边,若在右边则从凸包 P k + 1 P_{k+1} Pk+1 中抛出 p k p_k pk,继续迭代判断 p k + 1 p_{k+1} pk+1 p k − 1 − p k − 2 p_{k-1} - p_{k-2} pk1pk2 的哪边,直到在左边则结束迭代,最后剩下的即为凸包 P k + 1 P_{k+1} Pk+1

用栈存储中间过程的凸包计算, Q Q Q 中每个点仅会进出栈一次,故扫描为线性时间,主要耗时在排序。时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)。代码:

function GrahamScan(Q)P = Q[1 : 3]for q in Q[4 : end]while cross(q .- P[end], P[end] .- P[end - 1]) > 0pop!(P)endpush!(P, q)endreturn P
endfunction Graham(Q)m = argmin(last.(Q))p0, Q = Q[m], vcat(Q[begin : m - 1], Q[m + 1 : end])Q = sort(Q, lt = (p, q) -> cross(p .- p0, q .- p0) > 0)return GrahamScan(vcat(p0, Q))
end

分治算法

将当前点集均分为左右两部分,分别用分治算法得到各自的凸包,再将两个凸包合并成一个凸包。

合并过程是,取一边凸包上某一点作为基点,求另一边凸包上极角最大和最小的点,则一边凸包的点按基点的极角序有序,另一边凸包的点分为两条从极角最小到极角最大的极角序有序点集,将三个极角序有序点集按三路归并成一个极角序有序的点集,并进行 Graham Scan 算法流程。

时间函数 T ( n ) = T ( n 2 ) + O ( n ) T(n) = T(\frac{n}{2}) + O(n) T(n)=T(2n)+O(n),得时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn),但常数很大。代码:

function DC(Q)function argMaxMin(A, cmp)u, v = 1, 1for i = 2 : length(A)if cmp(A[i], A[u]) > 0u = iendif cmp(A[i], A[v]) < 0v = iendendreturn u, vendfunction merge3(A, B, C, cmp)ia, ib, ic = length(A), length(B), length(C)fa, fb, fc, R::typeof(A) = ia > 0, ib > 0, ic > 0, []while fa || fb || fcif fa && (!fb || cmp(A[ia], B[ib]) < 0) && (!fc || cmp(A[ia], C[ic]) < 0)push!(R, A[ia]); ia -= 1; fa = ia > 0elseif fb && (!fc || cmp(B[ib], C[ic]) < 0)push!(R, B[ib]); ib -= 1; fb = ib > 0elsepush!(R, C[ic]); ic -= 1; fc = ic > 0endendreturn reverse(R)endfunction CH(Q)if length(Q) <= 3m = argmin(last.(Q))p0, Q = Q[m], vcat(Q[begin : m - 1], Q[m + 1 : end])if length(Q) == 2 && cross(Q[1] .- p0, Q[2] .- p0) < 0Q = reverse(Q)endreturn vcat(p0, Q)endm = length(Q) ÷ 2L, R = CH(Q[begin : m]), CH(Q[m + 1 : end])if L[1][2] > R[1][2]L, R = R, Lendp0, L = L[1], L[2 : end]u, v = argMaxMin(R, (p, q) -> cross(p .- p0, q .- p0))slice(A, l, r) = l <= r ? A[l : r] : vcat(A[l : end], A[begin : r])R0, R1 = slice(R, u, v), slice(R, v, u)[end - 1 : -1 : begin + 1]return GrahamScan(vcat(p0, merge3(L, R0, R1, (p, q) -> cross(p .- p0, q .- p0))))endQ = sort(Q, by = first)return CH(Q)
end

实验测试

随机在 { ( x , y ) ∣ 0 ≤ x , y < 100 } \{ (x, y) | 0 ≤ x, y < 100 \} {(x,y)∣0x,y<100} 区域生成 3000 个点,测试各算法凸包结果和效率。代码:

using Random
function genData(n)Random.seed!(2024)return [q for q in zip(100 * rand(n), 100 * rand(n))]
end
Q = genData(3000)
@time P1 = NE(Q)
@time P2 = Jarvis(Q)
@time P3 = Graham(Q)
@time P4 = DC(Q)
@show length(P1)
@show length(P2), P2 == P1
@show length(P3), P3 == P1
@show length(P4), P4 == P1

结果:

  0.684359 seconds (585.47 k allocations: 40.423 MiB, 8.73% gc time, 53.56% compilation time)0.047316 seconds (27.23 k allocations: 2.719 MiB, 97.94% compilation time)0.175105 seconds (142.39 k allocations: 9.483 MiB, 3.61% gc time, 96.17% compilation time)0.412407 seconds (423.40 k allocations: 25.049 MiB, 98.20% compilation time)
length(P1) = 19
(length(P2), P2 == P1) = (19, true)
(length(P3), P3 == P1) = (19, true)
(length(P4), P4 == P1) = (19, true)

相关文章:

二维凸包算法 Julia实现

问题描述&#xff1a;给定平面上 n n n 个点的集合 Q Q Q&#xff0c;求其子集 P P P 构成 Q Q Q 的凸包&#xff0c;即 ∀ p ∈ Q , ∃ p 0 , p 1 , p 2 ∈ P \forall p \in Q, \exist p_0, p_1, p_2 \in P ∀p∈Q,∃p0​,p1​,p2​∈P 使得点 p p p 在以点 p 0 , p 1 …...

python dash框架

Dash 是一个用于创建数据分析型 web 应用的 Python 框架。它由 Plotly 团队开发&#xff0c;并且可以用来构建交互式的 web 应用程序&#xff0c;这些应用能够包含图表、表格、地图等多种数据可视化组件。 Dash 的特点&#xff1a; 易于使用&#xff1a;Dash 使用 Python 语法…...

2.外部中断(EXTI)

理论 NVIC&#xff1a;嵌套向量中断控制器&#xff08;解释教程&#xff09; 外部通用中断线(EXTI0~EXTI15)&#xff1a;每个GPIO设置成中断模式&#xff0c;与中断控制器连接的线 外部中断触发方式 上升沿触发、下降沿触发、双边沿触发 外部中断触发函数 在stm32f1xx_it.c文件…...

Python | SyntaxError: invalid syntax 深度解析

Python | SyntaxError: invalid syntax 深度解析 在Python编程中&#xff0c;SyntaxError: invalid syntax是一个常见的错误&#xff0c;它表明Python解释器在尝试解析代码时遇到了语法问题。这个错误通常是由于代码中存在拼写错误、缺少符号&#xff08;如括号、冒号或逗号&a…...

付费进群系统源码原版最新修复全开源版

付费进群&#xff0c;和平时所见到的别人拉你进群是不一样的&#xff0c;付费进群需要先缴费以后&#xff0c;才会看到群的二维码&#xff0c;扫码进群或者是长按二维码图片识别进群&#xff0c;付费进群这个功能广泛应用于拼多多的砍价群&#xff0c;活动的助力群&#xff0c;…...

Docker容器部署的SpringBoot项目jar包,上传文件但是找不到路径的问题

在docker容器内部署的jar包运行后&#xff0c;请求访问都没有问题&#xff0c;在文件上传时&#xff0c;发现上传图片接口响应成功&#xff0c;但是图片路径报404错误&#xff0c;发现找不到路径。 在服务器上查看也没有找到相关图片。 原因&#xff1a; 启动docker镜像时没…...

云计算学习——5G网络技术

系列文章目录 提示&#xff1a;仅用于个人学习&#xff0c;进行查漏补缺使用。 Day1 网络参考模型 Day2 网络综合布线与应用 Day3 IP地址 Day4 华为eNSP网络设备模拟器的基础安装及简单使用 Day5 交换机的基本原理与配置 Day6 路由器的原理与配置 Day7 网络层协议介绍一 Day8 传…...

matlab仿真 信道编码和交织(上)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第八章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; ​​​ ​ ​ ​ clear all N10;%信息比特的行数 n7;%hamming码组长度n2^m-1 m3;%监督位长度 [H,G]hammgen(m);%产生(n,n-…...

基于YOLOv8的高压输电线路异物检测系统

基于YOLOv8的高压输电线路异物检测系统 (价格88) 包含 【“鸟窝”&#xff0c;“风筝”&#xff0c;“气球”&#xff0c;“垃圾”】 4个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数…...

23款奔驰GLS450加装原厂电吸门配置,提升车辆舒适性和便利性

今天是一台22款奔驰GLS450&#xff0c;车主是佛山的 以前被不良商家坑了 装了副厂的电吸门 刚开始就很正常 用了半年之后 就开始开不了门&#xff0c;被锁在里面&#xff0c;刚开始车主以为是零件坏了 后来越来越频繁&#xff0c;本来是为了家里老人小孩关门方便而升级的&#…...

git操作流程笔记

1、在本地项目文件夹右击鼠标点击Git Bash Here 2、输入git init&#xff0c;这个目录变成git可以管理的仓库&#xff0c;会出现一个.git文件夹&#xff0c;如果没出现的话需要选择“显示隐藏文件”&#xff08;不会的同学自行百度一下&#xff09; 3、绑定本地仓库与远程仓库…...

【QT】常用控件-上

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 目录 &#x1f449;&#x1f3fb;QWidgetenabledgeometryrect制作上下左右按钮 window frame 的影响window titlewindowIcon代码示例: 通过 qrc 管理图片作为图标 windowOpacitycursor使用qrc自…...

帮助网站提升用户参与度的5个WordPress插件

仅靠编写精彩的内容、设计精美的图像和创建简化的客户旅程不足以提高网站参与度。您需要让用户在首次访问后继续与您的网站互动并成为回访者&#xff0c;才能真正吸引您所追求的兴趣。 幸运的是&#xff0c;对于 WordPress 用户来说&#xff0c;有数百种工具可用于提高用户参与…...

理解 Python 中的 @wraps:保留函数元数据

一.介绍 在本文中&#xff0c;我们将了解 wraps。在 Python 中使用装饰器时&#xff0c;您可能会遇到原始函数的元数据丢失的情况。这时&#xff0c;functools 模块中的 wraps 装饰器就可以派上用场了。让我们深入了解 wraps 的作用及其重要性。 二.简单装饰器的问题 首先&a…...

cjson

文章目录 概述编译cjson_test 小结 概述 在网络传输中&#xff0c;网络数据序列化&#xff0c;常用的有那么几种&#xff0c;json&#xff0c;protobuf都是很常用的&#xff0c;这一篇来写下json。 Json常用的有几个&#xff0c;rapidjson&#xff0c;jsoncpp&#xff0c;还有…...

Docker data root 目录更改

有时候受限于系统根目录空间的限制&#xff0c;需要将 docker data root 目录更改为其它目录&#xff0c;如单独挂载一个磁盘或存储。本篇文章介绍如何操作。 修改docker 工作目录 修改配置文件/etc/docker/daemon.json&#xff08;在19.x 版本之前使用grapth&#xff09; {&q…...

[CR]厚云填补_SEGDNet

Structure-transferring edge-enhanced grid dehazing network Abstract 在过去的二十年里&#xff0c;图像去雾问题在计算机视觉界受到了极大的关注。在雾霾条件下&#xff0c;由于空气中水汽和粉尘颗粒的散射&#xff0c;图像的清晰度严重降低&#xff0c;使得许多计算机视觉…...

图-基础概念

是什么 图是一种抽象的数据类型&#xff0c;在图中的数据元素通常称作节点&#xff0c;V是所以定点的集合&#xff0c;E是所有边的集合 图的分类 有向图 如果两个订单v&#xff0c;w&#xff0c;只能由v向w&#xff0c;而不能w向v&#xff0c;那么我们就把何种情况叫做一个从…...

Javascript前端基础面试(十)

MVVM Vue MVVM这一篇就够啦&#xff01;_vue r mvvm-CSDN博客 点容器内的图标,图标边框变成border 1px solid red&#xff0c;点空白处重置 <div id"container"> <img src"icon.png" alt"Icon" class"icon"> <!…...

书生大模型实战营闯关记录----第五关:LlamaIndex+Internlm2 RAG实践Demo:效果对比,文档加载,向量库构建,检索器,模型推理

文章目录 1. 前置知识RAG背景RAG 效果比对 2. 环境、模型准备2.1 配置基础环境2.2 安装 Python环境和依赖包2.3 下载 Sentence Transformer 模型2.4 下载 NLTK 相关资源 3. LlamaIndex HuggingFaceLLM4. LlamaIndex RAG加载文档构建向量存储索引库检索器RAG代码 5. LlamaIndex …...

如何让2008-2017年的老款Mac重获新生?OpenCore Legacy Patcher终极指南

如何让2008-2017年的老款Mac重获新生&#xff1f;OpenCore Legacy Patcher终极指南 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为手中的老款Mac无法安装最新macOS…...

Go HTTP Server 性能分析与优化

Go HTTP Server 性能分析与优化 在当今高并发的互联网应用中&#xff0c;HTTP Server的性能直接决定了用户体验和系统稳定性。Go语言凭借其轻量级协程和高效的网络库&#xff0c;成为构建高性能HTTP服务的首选之一。即使使用Go&#xff0c;开发者仍需深入分析性能瓶颈并进行针…...

5大实战技巧让你精通FDS火灾动力学模拟技术

5大实战技巧让你精通FDS火灾动力学模拟技术 【免费下载链接】fds Fire Dynamics Simulator 项目地址: https://gitcode.com/gh_mirrors/fd/fds 当一场突如其来的火灾发生时&#xff0c;传统的消防设计往往只能依靠经验估算&#xff0c;而FDS&#xff08;Fire Dynamics S…...

赣州琴行哪家最可靠

在赣州&#xff0c;选择一家可靠的琴行对于孩子的钢琴启蒙和成长至关重要。今天我们就来聊聊赣州的几家知名琴行&#xff0c;看看哪家最适合您的孩子。1. 可六琴行&#xff1a;专注儿童钢琴启蒙&#xff0c;天天练琴模式为什么选择可六琴行&#xff1f;1.1 专注儿童钢琴启蒙具体…...

Seafile社区版12.0部署实战:从Docker Compose到企业级定制

1. 为什么选择Seafile社区版12.0&#xff1f; 如果你正在寻找一个开源的、可私有化部署的企业级文件同步与共享解决方案&#xff0c;Seafile社区版12.0绝对值得考虑。作为一个长期使用各种云存储解决方案的运维工程师&#xff0c;我发现Seafile在性能、稳定性和功能完整性方面都…...

幻境·流金惊艳效果:微观世界视角——细胞结构、晶体生长、电路板纹路超清生成

幻境流金惊艳效果&#xff1a;微观世界视角——细胞结构、晶体生长、电路板纹路超清生成 “流光瞬息&#xff0c;影画幻成。” 想象一下&#xff0c;你正透过一台超级显微镜&#xff0c;观察一个我们肉眼无法触及的微观世界。在那里&#xff0c;细胞壁的纹理如同精密的蜂巢&…...

AcousticSense AI避坑指南:常见问题解决,确保你的音乐识别流程顺畅运行

AcousticSense AI避坑指南&#xff1a;常见问题解决&#xff0c;确保你的音乐识别流程顺畅运行 关键词&#xff1a;AcousticSense AI、音乐流派识别、问题排查、音频处理、ViT模型、梅尔频谱图、故障解决、部署指南 摘要&#xff1a;部署AcousticSense AI进行音乐流派识别时&…...

springboot-vue基于web的天气预报气候研究系统

目录系统架构设计技术栈选择功能模块划分数据库设计接口设计规范前端实现要点后端实现要点部署方案扩展性考虑测试计划项目时间规划注意事项项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作系统架构设计 采用前后端分离架构&am…...

C++ 编译器优化选项详解

C 编译器优化选项详解 在C开发中&#xff0c;编译器优化是提升程序性能的关键手段之一。通过合理配置优化选项&#xff0c;开发者可以在不修改代码逻辑的情况下&#xff0c;显著提高程序的运行效率&#xff0c;减少资源消耗。本文将深入探讨C编译器的优化选项&#xff0c;帮助…...

C++ constexpr 在工程中的应用场景

C constexpr 在工程中的应用场景 在现代C开发中&#xff0c;constexpr关键字因其强大的编译时计算能力&#xff0c;逐渐成为提升性能与代码可维护性的利器。它允许开发者在编译期完成复杂的计算和初始化&#xff0c;从而减少运行时开销&#xff0c;同时增强代码的静态安全性。…...