二维凸包(Graham) 模板 + 详解

news2024/11/17 17:42:28

(闲话)

上了大学后没怎么搞oi,从土木跑路到通信了(提桶开润大成功!),但是一年上两年的课(补的),保研也寄掉了(

说起来自从博客被大学同学发现并在我面前一个一个字读了以后,我:这谁写的,太他ma二次元了,本人决定以后就用比较正常的表述来写这些了(

最近在裸打acm,然后因为只会数据结构派不上用场被队友叫去整点其他部分内容,这两天随便摸了个凸包,整理一下Graham算法,例题还是洛谷的,顺便丢上自己的代码解释步骤:

一、找最低点(y值为min)做起始点root

root必在凸包上就在读入的时候顺便处理掉就行了。为了能顺利找到,root先赋一个大于所有y的值即可。如果出现最低点有很多个,记得一定要找x值最小/最大的点,不然遇到hack数据就没了(原因存疑,个人猜想保留)

for (int a = 1 ; a <= n ; ++ a) {
	scanf("%lf%lf",&s[a].x,&s[a].y);
	if (s[a].y < s[root].y || (s[a].y == s[root].y && s[a].x < s[root].x)) root = a;
} //.x的地方换成大于号也可

此处的s是定义的结构体point,顾名思义。其中的v是存的斜率。这玩意儿干啥用的之后再说

struct point {
	double x,y,v;
};

二、Grahamの排序

排序是精髓。Graham用的排序是以root点为基准,按照其他点和它连线的斜率来决定先扫哪个点再扫哪个点的,这样优势很明显,我意会了一下就记住了,具体原理没找,就不讲了,记得按照斜率扫就行了(

所以,我们要根据这个斜率对原来的一堆点进行排序。我用的是atan2,当然自己算角也行,就是麻烦点。根据下列引用可以得知,atan2如果将点集排序成从右往左扫,它的值是从0升到π,这个值用上文中的结构体point里的v存着。排序的时候cmp按照.v排序就行了。

顺便说一声,直接排的话,遇到斜率相同的点会乱序,遇到hack数据就寄了,所以排序是按照先排斜率再排比较的两点各自与root的距离。

Graham按极角排序但不用距离作为第二关键字会错的原因

/*先按照斜率.v进行比较,再按照距离进行比较*/
bool cmp(point x,point y) {
    return x.v == y.v ? dis(x,s[1]) < dis(y,s[1]) : x.v < y.v;
}

sort(s + 2,s + n + 1,cmp);    //第一个点是root,不用排

那排序就很简单地完成了

三、扫描搜点构成凸包

接下来就是对排序的点遍历,开始包了。我们每次加的点都要满足能构成“当前的凸包”,我是从右往左扫的,所以。。不对,在这之前先介绍二维的叉积吧

就是这么个玩意儿:A.x * B.y - B.x * A.y,AB为俩向量

如果叉出来的结果为正,说明A正旋到B<180°;结果为负,说明A正旋到B>180°。正旋就是从x正向往y正向那方向转

咱以从右往左扫为例,我们要整的凸包此时新的一段一定是要更“往左边拐的”,就是新的凸包边应该是上一个凸包边正旋小于180°能得到的

于是我们把已经构成的凸包的最新的一段,和将要连上的一段整成两个向量(都是从先构造到的点指向后构造的点),叉一下,如果结果为负或0,就说明我们新的边“往右拐”了,这样上一次的凸包的电就不在新的凸包边集上了。而且此时有可能再上一次的边也不满足要求,就还得倒回去接着叉(此时构造向量时,要将之前排除的点的相关部分给换成当前判断的点)。大概是这个样子:

这判断就是jud函数里面的return那部分。为了防止栈被掏空,溯源到root就不继续判断了。

具体代码部分见下:

bool jud(point a,point b,point c,point d) {
	double ix = b.x - a.x,iy = b.y - a.y;
	double jx = d.x - c.x,jy = d.y - c.y;
	return (ix * jy - iy * jx) <= 0;
} //我把向量构成搬到里面来了,小于等于0即判断向量正旋类型

    for (int a = 2 ; a <= n ; ++ a) {
		while (tot > 1 && jud(已处理点构成的向量,新处理点构成的向量) --tot;
		que[++tot] = s[a];
	}

que即为存凸包上的点的栈

四、Blabla

总之这样凸包就已经求出来了,根据题目要求算出要算的东西就行了。 放下上文例题代码:

#include <algorithm>
#include <cstdio>
#include <cmath>
#define N 100010
using namespace std;
struct point {
	double x,y,v;
} s[N],que[N << 1];
double ans = 0;
int n,root = 0,tot = 0;
void swap(point &x,point &y) {point z = x; x = y,y = z;} 
double pf(double x) {return x * x;}	//平方 
double dis(point i,point j) {return sqrt(pf(i.x - j.x) + pf(i.y - j.y));}	//求两点距离 
bool cmp(point x,point y) {return x.v == y.v ? dis(x,s[1]) < dis(y,s[1]) : x.v < y.v;}
bool jud(point a,point b,point c,point d) {
	double ix = b.x - a.x,iy = b.y - a.y;
	double jx = d.x - c.x,jy = d.y - c.y;
	return (ix * jy - iy * jx) <= 0;	//判断正旋角度是否满足题意 
}
int main() {
	s[0].x = 1e6 + 1;
	s[0].y = 1e6 + 1;
	scanf("%d",&n);
	for (int a = 1 ; a <= n ; ++ a) {	//读入点并确定root 
		scanf("%lf%lf",&s[a].x,&s[a].y);
		if (s[a].y < s[root].y || (s[a].y == s[root].y && s[a].x < s[root].x)) root = a;
	}
	swap(s[1],s[root]);
	que[++tot] = s[1];	//root入栈
	 
	for (int a = 2 ; a <= n ; ++ a)	//计算每点与root的斜率 
		s[a].v = atan2(s[a].y - s[1].y,s[a].x - s[1].x);
	sort(s + 2,s + n + 1,cmp);	//按斜率排序 
	
	for (int a = 2 ; a <= n ; ++ a) {	//从右往左扫描 把点丢进凸包 再丢出来一些 
		while (tot > 1 && jud(que[tot - 1],que[tot],que[tot],s[a])) --tot;
		que[++tot] = s[a];
	}
	
	/*根据本题要求求出凸包周长*/
	que[++tot] = s[1];
	for (int a = 1 ; a < tot ; ++ a) ans += dis(que[a],que[a + 1]);
	printf("%.2lf\n",ans);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1018529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

地牢大师问题(bfs提高训练 + 免去边界处理的特殊方法)

地牢大师问题 文章目录 地牢大师问题前言题目描述题目分析输入处理移动方式【和二维的对比】边界判断问题的解决 代码总结 前言 在之前的博客里面&#xff0c;我们介绍了bfs 基础算法的模版和应用,这里我们再挑战一下自己&#xff0c;尝试一个更高水平的题目&#xff0c;加深一…

vue2——电商项目 黑马

创建项目 初始化 router app.vue vant 组件库 Viewport 布局 vw适配 路由配置 底部导航组件 二级路由配置 登录页面 新建默认样式 main.js 引入commonless 登录静态页面—头部组件NavBar 导入navbar 引用 axios封装 图形验证码 获取 get 渲染 api接口模块 toast轻提示 使用 …

Flutter图标

https://fluttericon.cn/ Flutter 内置了丰富的图标。 Icon(Icons.ac_unit)

智能批量重命名,轻松删除文件名后缀数字并添加编号!

亲爱的用户们&#xff0c;您是否曾经为繁琐而重复的文件重命名工作而感到头疼&#xff1f;现在&#xff0c;我们为您提供一款智能化的工具&#xff0c;让文件重命名变得如此简单&#xff01; 首先&#xff0c;我们要进入文件批量改名高手&#xff0c;并在板块栏里选择“文件批…

overleaf 插入图片,引用图片,图标标题Fig与文章引用Figure不一致解决

目录 1.一般插图 2.插入双栏图片 3 插入子图 4. 引用出现问题 问题1 &#xff1a; pdf 文中引用只出现了图片序号&#xff0c;如“3”。没有出现“Fig.3 或者Figure.3” 问题2&#xff1a;文中引用的标题和图片下面的标题不一致 1 首先&#xff0c;在导言区添加以下行…

七天学会C语言-第二天(数据结构)

1. If 语句&#xff1a; If 语句是一种条件语句&#xff0c;用于根据条件的真假执行不同的代码块。它的基本形式如下&#xff1a; if (条件) {// 条件为真时执行的代码 } else {// 条件为假时执行的代码 }写一个基础的If语句 #include<stdio.h> int main(){int x 10;…

HarmonyOS开发环境搭建

一 鸿蒙简介&#xff1a; 1.1 HarmonyOS是华为自研的一款分布式操作系统&#xff0c;兼容Android&#xff0c;但又区别Android&#xff0c;不仅仅定位与手机系统。更侧重于万物物联和智能终端&#xff0c;目前已更新到4.0版本。 1.2 HarmonyOS软件编程语言是ArkTS&#xff0c…

STM32DMA原理和应用

目录 1.什么是DMA 2.DMA的意义 3.DMA搬运的数据和方式 4.DMA 控制器和通道 5.DMA通道的优先级 6.DMA传输方式 7.DMA应用 实验一: 内存到内存搬运 CubeMX配置&#xff1a; ​编辑用到的库函数&#xff1a; 代码实现思路&#xff1a; 实验二: 内存到外设搬运 CubeMX…

简单返回封装实体类(RespBean)

RespBean的作用 返回状态码&#xff0c;返回信息&#xff0c;返回数据 package com.example.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public class RespBean {private lon…

基于springboot实现的极验校验

概述 在系统业务中&#xff0c;需要想客户发送手机验证码&#xff0c;进行验证后&#xff0c;才能提交。但为了防止不正当的短信发送&#xff08;攻击&#xff0c;恶意操作等&#xff09;&#xff0c;需要在发送短信前添加一个行为验证&#xff08;这里使用的是极验&#xff0…

利用Python将dataframe格式的所有列的数据类型转换为分类数据类型

一、样例理解 import pandas as pd import numpy as np# 创建测试数据 feature_names [col1 , col2, col3, col4, col5, col6] values np.random.randint(20, size(10,6))dataset pd.DataFrame(data values, columns feature_names)print("转换前的数据为\n",d…

【C进阶】指针和数组笔试题解析

做题之前我们先来回顾一下 对于数组名的理解&#xff1a;除了以下两种情况&#xff0c;数组名表示的都是数组首元素的地址 &#xff08;1&#xff09;sizeof&#xff08;数组名&#xff09;&#xff1a;这里的数组名表示整个数组 &#xff08;2&#xff09;&&#xff08;数…

Maven3.6.1下载和详细配置

1.下载maven 说明&#xff1a;以下载maven3.6.1为例 1.1网址 Maven – Welcome to Apache Maven 1.2点击下载 1.3点击Maven 3 archives 1.4 点击相应的版本 1.5 点击binaries下载 说明&#xff1a;binaries是二进制的意思 1.6点击zip格式 1.7 蓝奏云获取 说明&#xff1a…

C语言——自定义类型结构体_学习笔记

结构体的基本概念 结构体是一种用户自定义的数据类型&#xff0c;可以包含多个不同类型的变量。通过使用结构体&#xff0c;我们可以将相关联的数据组织在一起&#xff0c;便于管理和使用。 结构体的声明 正常的结构体声明 在C语言中&#xff0c;结构体(struct)指的是一种数…

【SA8295P 源码分析】97 - QNX AIS Camera 框架介绍 及 Camera 工作流程分析

【SA8295P 源码分析】97 - QNX AIS Camera 框架介绍 及 Camera 工作流程分析 一、QNX AIS Server 框架分析二、QNX Hypervisor / Android GVM 方案介绍三、Camera APP 调用流程分析四、QCarCam 状态转换过程介绍五、Camera 加串-解串 硬件链路分析六、摄像头初始化检测过程介绍…

Debian环境下搭建STM32开发环境

1. 安装交叉编译工具&#xff0c;解压gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2&#xff0c;并且把交叉编译环境添加到path路径。 2.安装下载工具驱动和下载工具 # 安装下载工具openocd sudo apt -y install openocd 3.下载测试 sudo openocd -f cmsis-dap.cfg -…

吴恩达ChatGPT《Finetuning Large Language Models》笔记

课程地址&#xff1a;https://learn.deeplearning.ai/finetuning-large-language-models/lesson/1/introduction Introduction 动机&#xff1a;虽然编写提示词&#xff08;Prompt&#xff09;可以让LLM按照指示执行任务&#xff0c;比如提取文本中的关键词&#xff0c;或者对…

postgresql|数据库|centos7下基于postgresql-12的主从复制的pgpool-4.4的部署和使用

前言&#xff1a; postgresql数据库只用自身的一些配置是无法做到最优的优化的&#xff0c;需要通过一些外置插件&#xff08;中间件&#xff09;来提高服务器的整体性能&#xff0c;通俗的说就是数据库仅仅依靠自身是无法达到性能最优的&#xff0c;很多时候需要更改数据库的…

网工证书选择,就业岗位等相关说明

1.网工就业岗位说明。 2.未来职业走向等。 -- 厂商认证 -- HCIE - Datacom HCIE - Secuurity CCIE - EI等等 -- 通信行业 组网 产品 搞技术 - 迭代速度快 -- 厂商&#xff1a; 设计 制造 生产网络设备的公司 - 思科 华为 华三 锐捷等 -- 目的&#xff1a;找…

flink的main方法和execute方法的关系

背景&#xff1a; 执行flink时&#xff0c;我们几种执行模式&#xff0c;比如在IDE本地执行模式以及远程YARN执行的模式等&#xff0c;你是否有疑问&#xff0c;为什么他们可以共用相同的代码呢&#xff1f;其实这就涉及到main方法和execute方法的关系了 flink的main方法和ex…