凸包(Graham扫描法构建)

PS:我的妈呀,心态爆炸,好像也不太难,看各种模板看的云里雾里的,真的还是自己动手敲来的好,几乎没多久就懂的差不多了。。。。
一个本该寒假就该掌握的知识,居然熬了我几个小时。。。。。。。

这一次还是很好的了解了凸包,以前看群里学长们说,觉得好高大上,好难的样子,仔细了解后发现其实也没有想象中的那么恐怖

凸包基本概念:

这就是一个简单的凸包:

其实凸包求法有很多种:比如卷包裹法(时间复杂度O(n*n))、Graham扫描法(时间复杂度O(nlogn)、Jarvis步进法、Melkman算法(时间复杂度O(n))

好像Melkman算法要好一点,但是Graham扫描法更加实用,于是就找资料恶补了下:
步骤:


1、 把所有点放在二维坐标系中,则纵坐标最小的点一定是凸包上的点,如图中的P0。
2、 把所有点的坐标平移一下,使 P0 作为原点,如上图。
3、 计算各个点相对于 P0 的幅角 α ,按从小到大的顺序对各个点排序。当 α 相同时,距离 P0 比较近的排在前面。例如上图得到的结果为 P1,P2,P3,P4,P5,P6,P7,P8。我们由几何知识可以知道,结果中第一个点 P1 和最后一个点 P8 一定是凸包上的点。
(以上是准备步骤,以下开始求凸包)
4、 以上,我们已经知道了凸包上的第一个点 P0 和第二个点 P1,我们把它们放在栈里面。现在从步骤3求得的那个结果里,把 P1 后面的那个点拿出来做当前点,即 P2 。接下来开始找第三个点:
连接P0和栈顶的那个点,得到直线 L 。看当前点是在直线 L 的右边还是左边。
如果在直线的右边就执行步骤5;如果在直线上,或者在直线的左边就执行步骤6。
5、 如果在右边,则栈顶的那个元素不是凸包上的点,把栈顶元素出栈。执行步骤4。
6、 当前点是凸包上的点,把它压入栈,执行步骤7。
7、 检查当前的点 P2 是不是步骤3那个结果的最后一个元素。是最后一个元素的话就结束。如果不是的话就把 P2 后面那个点做当前点,返回步骤4。

步骤说明是参考这位大佬的博客:链接

Granham算法本质:

基本上就可以分为两个部分:
1、排序:(时间复杂度O(nlogn))
排序时,有两种排序方式:
1、极角序(目前这种排序好像比较常见):


2、水平序

2、扫描;(时间复杂度O(n))
扫描过程也就是上面步骤中逐步试探进栈出栈的过程;

虽然这些没多久就看懂了,但是写代码时,迟迟不敢动手,如果早些尝试,可能就不会耗这么长时间了⑧

于是边尝试,边看大牛的代码最终敲成了。。。。

当然这个代码是为了解决
给定若干点,求所构成的三角形面积的最大值

暴力时间复杂度O(nnn),很显然TLE
于是:通过求得凸包,然后在凸包中进行筛选,最后A了

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef struct
{double x,y;
}POINT;
POINT p[50010];
POINT result[50010];
/**叉乘*/
double multi(POINT p1,POINT p2,POINT p0)
{return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
/**求距离*/
double Distance(POINT a,POINT b)
{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
/**核心*/
int cmp(POINT a,POINT b)
{double x=multi(a,b,p[0]);/**接下来就是为什么Granham算法比较核心的部分了,正是因为这个排序才使得其时间复杂度大大降低*/if(x>0)return 1;/**这就是在开始所说的共线问题的处理*/else if(x==0&&Distance(a,p[0])<Distance(b,p[0]))return 1;return 0;
}
int main()
{int n;while(~scanf("%d",&n)){for(int i=0;i<n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);/**p0表示纵坐标最小,横坐标最小的点*/POINT p0;p0.x=p[0].x;p0.y=p[0].y;int t=0;    //用来记录p0的位置,好最终与p[0]进行交换for(int i=1;i<n;i++){if(p[i].y<p0.y){p0.y=p[i].y;t=i;}else if(p[i].y==p0.y&&p[i].x<p0.x){p0.x=p[i].x;t=i;}}/**p[0]与p[t]进行交换,好方便之后的排序操作*/swap(p[0],p[t]);sort(p+1,p+n,cmp);   //排序/**扫描操作*/result[0]=p[0];result[1]=p[1];result[2]=p[2];int top=2;for(int i=3;i<n;i++){while(multi(p[i],result[top],result[top-1])>=0)top--;    //出栈result[++top]=p[i];     //圧栈}//到这凸包就已经构建完成了double s=0;for(int i=0;i<=top;i++){for(int j=0;j<=top&&j!=i;j++){for(int k=0;k<=top&&k!=j&&k!=i;k++){POINT A=result[i];POINT B=result[j];POINT C=result[k];double num=0.5*fabs(multi(B,C,A));   //0.5和fabs都得注意if(num>s)s=num;}}}printf("%.2f\n",s);}return 0;
}

可能又多掉了几根头发吧

凸包(Graham扫描法构建)相关推荐

  1. 凸包 Graham扫描法 TOJ 1255 Surround the TreesTOJ 3100 女生寝室的围墙

    凸包算法有很多种... 我就学了一种Graham扫描法..以不变应万变... 1.把所有点放在二维坐标系中,则纵坐标最小的点一定是凸包上的点,如图中的P0. 2.把所有点的坐标平移一下,使 P0 作为 ...

  2. java经纬度凸包graham_凸包算法(Graham扫描法)详解

    先说下基础知识,不然不好理解后面的东西 两向量的X乘p1(x1,y1),p2(x2,y2) p1Xp2如果小于零则说明  p1在p2的逆时针方向 如果大于零则说明 p1在p2的顺时针方向 struct ...

  3. 凸包算法-------Graham扫描法

    在网络上关于凸包解法多种多样,讲的也非常的不错,可以参考一下这篇博客,但是还是想用自己的话去描述一遍,以加深一下印象. 常见的解法有: 穷举法(蛮力法) 分治法 Jarvis步进法 Graham扫描法 ...

  4. 凸包与Graham扫描法求凸包

    前置芝士 凸多边形 凸多边形指的是所有内角都在 (0,π](0,\pi](0,π] 范围内的多边形. 凸包 对于一个平面上的一个给定的点集,他们对应的凸包就是能把他们全部包含的最小凸多边形. 如果形象 ...

  5. 转 最小凸包算法(Convex Hull)(1)-Graham扫描法 -计算几何-算法导论

    原文地址:http://blog.csdn.net/suwei19870312/article/details/542281 基本问题: 平面上有n个点p1,p2, ..., pn, 要求求出一个面积 ...

  6. 凸包模板(分治 or Graham扫描法)

    问题概述:空间上有很多点,现在要用一个凸多边形将所有点全部包住,求哪些点在这个凸多边形上 输入样例:                                             对应输出: ...

  7. 凸包算法(Graham扫描法)

    目录 一.概念 二.算法步骤 三.代码实现 转自:https://www.cnblogs.com/aiguona/p/7232243.html 一.概念 凸包(Convex Hull)是一个计算几何( ...

  8. Graham扫描法求解二维凸包问题

    最近在LeetCode的每日一题和实验中接连遇到凸包问题,因为之前从来没写过,于是写这篇博客记录一下,内容部分参考每日一题的官方题解和算法导论.算法的具体描述以及代码实现多为个人理解,如有谬误还请指出 ...

  9. 凸包问题 —— Graham扫描法

    凸包问题 -- Graham扫描法: (1)找出点集p[]中最左下的点p1,把p1同点集中其他各点用线段连接,并计算这些线段与水平线的夹角,然后按夹角从小到大和按到p1的距离从近到远排序(夹角范围为 ...

最新文章

  1. MyBatis框架添加客户有哪些步骤
  2. Android开发--PreferenceActivity中打开子PreferenceScreen黑屏的解决办法
  3. 二叉查找树Java实现代码
  4. lvs-健康检查方式
  5. [转]数据库主键设计文章绘粹
  6. Java技巧:提高J2SE性能的代码技巧
  7. sed和awk的常用实例 .
  8. 【剑指 offer】(十九)—— 二叉树镜像
  9. hive partition 分区详解一
  10. 25年面试官首次揭秘——世界500强面试题之微软面试题
  11. 【腾讯笔试题】记腾讯2019年暑假实习移动端开发在线笔试题
  12. Docker Are you trying to connect to a TLS-enabled daemon without TLS?
  13. be idle sometimes to_一生中不该错过的经典语录,深刻有道理,看了让人爱不释手!...
  14. 摩托罗拉Android系统,摩托罗拉Droid官方Android 2.2系统详细功能展示
  15. 第16周项目3--用函数指针调用函数(吃饭,睡觉,打豆豆)
  16. 移动硬盘加密方法加密后对硬盘读写的影响
  17. java switch枚举类,Java 枚举 switch的用法
  18. SMTP 与 ESMTP
  19. echarts图表生成base64
  20. 任正非霸气回应:没有谷歌,华为也能成为世界第一!

热门文章

  1. 自己编写代码去听网易云音乐的歌曲,以及观看MV,还可以下载奥
  2. Docker的基本使用
  3. 【安卓wechat微信导出聊天记录】
  4. Ubuntu22.04.01Desktop桌面版安装记录221109
  5. threejs学习笔记:实现导入的动画gltf模型播放动画
  6. 2023年全国最新二级建造师精选真题及答案
  7. 2023年全国最新二级建造师精选真题及答案56
  8. 为什么我要“安利”你们来实习?
  9. 用JS通过新浪天气API接口获取天气
  10. 微信小程序开发01 双线程模型:为什么小程序不用浏览器的线程模型?