关于graham扫描法求凸包的小记

时间:2022-09-03 08:53:01

1、首先,凸包是啥:

若是在二维平面上,则一般的,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。

───────────────────────────────────────────────────────────────────────────────────────────────────────────

2、那么,如何通过某种算法求二维平面上的凸包呢?

有Graham扫描法(Graham scan algorithm),复杂度O(nlogn)。

话不多说,先上当年大佬的论文……

关于graham扫描法求凸包的小记

呃,可以看到,这个标题是非常的酷嗷,对于有限平面点集的凸包计算的高效算法,划重点。

关于graham扫描法求凸包的小记

给一个平面点集S,标号为s1~sn,据说我们经常对找它的凸包感兴趣(真的吗……我怎么从来没感兴趣过……)

然后graham教授就给了我们一种炫酷的五步法,来求凸包。

关于graham扫描法求凸包的小记

第一步:

  目标是找个在凸包内部的点P。

  我们对集合S三个点三个点进行检测,检测它们是否共线:

    若共线,扔掉中点;

    若不共线,就选这三个点所组成的三角形的质心作为点P。

关于graham扫描法求凸包的小记

第二步:

  以P为原点,任意一个方向为θ=0轴,建立一个极坐标系;

  对集合S中的每个点si,都按这个坐标系表示一下它们的坐标。

关于graham扫描法求凸包的小记关于graham扫描法求凸包的小记

第三步:

  现在每个点都有坐标 r ∠ θ ,我们对这些点,按照θ的升序进行排序。

关于graham扫描法求凸包的小记

第四步:

  如果有某两个点的角度相等,就删掉r较小的那个点,因为它显然不可能是凸包边界上的点。

  另外呢,所有r=0的,也可以删了,反正也impossible。

  then,重新给还存在着的点编号,新的集合记为S'。

关于graham扫描法求凸包的小记           关于graham扫描法求凸包的小记

关于graham扫描法求凸包的小记

第五步:

  对于S'中连续的三个点k,k+1,k+2,如图2,有两种可能:

    1)α + β ≥ π,看图,就很容易知道,这个点k+1,显然不可能是凸包边界上的点了;

      回到步骤五,重新选择点k-1,k,k+2作为新的三个点;

    2)α + β < π,就回到步骤五,选择点k+1,k+2,k+3作为新的三个点;

      相当于往前进。

原文件:https://files.cnblogs.com/files/dilthey/graham%E6%89%AB%E6%8F%8F%E6%B3%95.pdf

───────────────────────────────────────────────────────────────────────────────────────────────────────────

3、那么放到程序中,具体如何实现呢?

我们保留“对于三个点,判断角α、β和是否小于180度,并且进行相应的前进退后”的思想,不过对于选取原点的方法进行一定的修改。

  ①找到点集S中纵坐标最小的点(如果y坐标相同,则选其中横坐标最小的),作为原点P0

  ②计算其他所有点的辐角,并且将他们按从小到大排序,如果遇到辐角相同的一些点,则按与原点距离从小到大排序,记为P1~Pn

  ③建栈,入栈P0,P1,P2

  ④选取一个点Pi(i初始值为3),前往步骤⑤;

  ⑥获得栈顶点和次栈顶点Pk,Pk-1

    进行判定:如果 Pk-1 -> P-> P是右转的(其实就是α + β ≥ π),就弹出栈顶元素,并且返回步骤⑥;

         如果是左转的(α + β < π),就入栈点Pi,并且i+=1,返回步骤④;

───────────────────────────────────────────────────────────────────────────────────────────────────────────

4、代码模板:

#include<bits/stdc++.h>
#define MAX 10005
#define eps 1e-6
using namespace std;
struct Point{
double x,y;
Point(double tx=,double ty=):x(tx),y(ty){}
}p[MAX];
typedef Point Vctor;
Vctor operator - (Point A,Point B){return Vctor(A.x-B.x,A.y-B.y);}
int dcmp(double x)
{
if(fabs(x)<eps) return ;
else return (x<)?(-):();
}
//叉积
double Cross(Vctor A,Vctor B){return A.x*B.y-A.y*B.x;}
//距离
double dist(Point p1,Point p2){return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}
bool cmp(Point p1,Point p2)
{
double tmp=Cross(p1-p[],p2-p[]);
if(!dcmp(tmp)) return dist(p[],p1)<dist(p[],p2);
else return tmp>;
}
vector<Point> graham_scan(int n)
{
vector<Point> ans; if(n<=) return ans;
if(n<=)//当只有1或2个点时
{
if(n== && (p[].y<p[].y || (p[].y == p[].y && p[].x < p[].x)) ) swap(p[],p[]);
for(int i=;i<n;i++) ans.push_back(p[i]);
return ans;
} int idx=;
for(int i=;i<n;i++)//选出Y坐标最小的点,若Y坐标相等,选择X坐标小的点
{
if(p[i].y<p[idx].y || (p[i].y == p[idx].y && p[i].x < p[idx].x)) idx=i;
}
swap(p[],p[idx]);
sort(p+,p+n,cmp);
for(int i=;i<=;i++) ans.push_back(p[i]);
int top=;
for(int i=;i<n;i++)
{
while(top> && Cross(p[i]-ans[top-],ans[top]-ans[top-]) >= )
{
ans.pop_back();
top--;
}
ans.push_back(p[i]);
top++;
}
return ans;
}

关于graham扫描法求凸包的小记的更多相关文章

  1. (模板)poj1113(graham扫描法求凸包)

    题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code ...

  2. Graham扫描法 --求凸包

    前言: 首先,什么是凸包? 假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来.当这个多边形是凸多边形的时候,我们就叫它“凸包”.如下图:  然后,什么是凸包 ...

  3. 使用Graham扫描法求二维凸包的一个程序

    #include <iostream> #include <cstring> #include <cstdlib> #include <cmath> # ...

  4. Graham 扫描法找凸包&lpar;convexHull&rpar;

    凸包定义 通俗的话来解释凸包:给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点  Graham扫描法 由最底的一点 \(p_1\) 开始(如果有多个这样的点, ...

  5. &lbrack;BZOJ1069&rsqb;&lbrack;SCOI2007&rsqb;最大土地面积&lpar;水平扫描法求凸包&plus;旋转卡壳&rpar;

    题意:在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成. 的多边形面积最大.n<=2000. 先求凸包,再枚举对角线,随着对角线的斜率上升,另外两 ...

  6. nyoj-78-圈水池(Graham算法求凸包)

    题目链接 /* Name:nyoj-78-圈水池 Copyright: Author: Date: 2018/4/27 9:52:48 Description: Graham求凸包 zyj大佬的模板, ...

  7. &lbrack;poj1113&rsqb;&lbrack;Wall&rsqb; &lpar;水平序&plus;graham算法 求凸包&rpar;

    Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...

  8. (模板)graham扫描法、andrew算法求凸包

    凸包算法讲解:Click Here 题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是 ...

  9. 【BZOJ-1670】Building the Moat护城河的挖掘 Graham扫描法 &plus; 凸包

    1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 464  Solv ...

随机推荐

  1. Visual Studio 2013 无法正常打开项目文件

    提示:无法打开 vcxproj 因为此版本的应用程序不支持其项目类型 ,若要打开它 请使用支持此类型项目的版本. 检查  AppData\Roaming\Microsoft\VisualStudio\ ...

  2. ruby在线学习

    http://tryruby.org/ [Heroku空间] 免费ruby空间

  3. 【考试】简单的sql语句

    )显示正好为5个字符的员工的姓名 HR@ORA11GR2>select last_name,first_name from employees ; )显示不带有"R"的员工的 ...

  4. crtmpserver组网方案

    A Powerful Live Streaming Setup 搭建强大的直播系统 Recently we had a project requiring live streaming setup, ...

  5. django中命令行调试程序

    (1)进入到程序manage.py所在的目录下 (2)python manage.py shell 这样可在命令行中引入models.views.class等所有的包,然后进行命令行试运行.

  6. bzoj千题计划172:bzoj1192&colon; &lbrack;HNOI2006&rsqb;鬼谷子的钱袋

    http://www.lydsy.com/JudgeOnline/problem.php?id=1192 1,2,4,8,…… n-2^k 可以表示n以内的任意数 若n-2^k 和 之前的数相等,一个 ...

  7. OAF&lowbar;OAF增删改-修改的实现(案例)

    2014-06-02 Created By BaoXinjian

  8. 在 Eclipse Juno 上安装 Marketplace

    Select Help/Install new software... from the menu, select the Juno update site (http://download.ecli ...

  9. thinkphp5 前台模板的引入css&comma;js&comma;images

    一:在公共的静态文件夹中建立我们模块的名称用来放置css,js,images 二:在配置文件config中定义需要的路径 三:在视图页面引入

  10. &lbrack;转&rsqb;SQL Server 性能调优(io)

      目录 诊断磁盘io问题 常见的磁盘问题 容量替代了性能 负载隔离配置有问题 分区对齐配置有问题 总结 关于io这一块,前面的东西如磁盘大小,磁盘带宽,随机读取写入,顺序读取写入,raid选择,DA ...