凸包的概念

首先,引入凸包的概念:

(有点窄的时候...图片右边可能会被吞,拉开图片看就可以了)

大概长这个样子:

那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包)

Andrew算法流程和思想

常见的求凸包的算法有$Graham$和$Andrew$,$Andrew$是$Graham$扫描算法的变种,和$Graham$相比,$Andrew$更快,且更稳定,所以主要讲一下$Andrew$。

首先把所有点以$x$坐标为第一关键字,$y$坐标为第二关键字从小到大进行排序,可以肯定第一个点和最后一个点在答案中。

接下来用以下的例子来帮助理解算法流程:

第一次,把$1$和$2$加入答案中

尝试把$3$加进去,发现凹进去了,所以把$2$丢掉,把$3$放进去

我们来看看$2$被丢掉,$3$成功上位的原因(凹进去的原因):
发现是斜率(或者...可以总结成叉积?

在下图中$1->2$的斜率大于$1->3$的斜率,又因为之前按$x$递增排序,所以可以说明$2$在$3$的左上,所以是凹进去的。

换句话说,如果加进去这个点(即当前点,记为$i$)和$i-2$号点的斜率小于$i$号点和$i-1$号点的斜率,那么就要把$i-1$号点去掉并加入$i$号点来维护凸包的性质(不让它凹进去)

接下来加入$4$,$1->4$斜率大于$1->3$斜率,所以$3$不用被丢掉。

加入$5$,$3->5$斜率小于$3->4$斜率,所以丢掉$4$,加入$5$

加入$6$,一样的理由,一样的操作。($3->6$斜率小于$3->5$斜率,丢掉$5$,加入$6$)

然后发现$3$那个地方也凹进去了($1->6$的斜率小于$1->3$的斜率)

所以$3$也要被丢掉,然后只剩下两个点:

(所以写代码的时候要用$while$)

接着来,加入$7$:

然后是$8$,发现...斜率只小一点点(图没画好,这刁钻的角度,将就看一下吧...),所以$7$要删掉

不过也顺便解决一个共线的问题,共线嘛,很好解决,反正两个点都在凸包上,都不丢就可以了,后面如果那一条线不属于凸包的话,用$while$丢点的时候两个点斜率是一样的,总会被丢出去的。

然后是$9$,发现斜率小,所以丢掉$8$:

啊哈,然后发现所有点都已经遍历完了,成功达到了$9$,可是凸包还有一半呢。

倒着再来一次就可以求出上面那个盖盖了:

(下面放流程图,不一一解说了(好累),操作是一样的)

(把$7$悄悄地挪了一下位置)

(丢掉$6$,发现斜率的关系和正着的那一次都一样,都是小于)

这样, 凸包就求出来啦!

按照以上的思路写代码就可以啦。

例题& 板子

例题: 求凸包的周长:

 /*
ID: Starry21
LANG: C++
TASK: fc
*/
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define N 10005
struct node{
double x,y;
};
node p[N],s[N]/*凸包上的点*/;
int n;
double dis(node a,node b)
{
return sqrt(((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)));
}
bool cmp(node a,node b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
double getk(node a,node b)
{
if(a.x==b.x) return INF;//在一条竖线上 斜率看成无限大
return (b.y-a.y)/(b.x-a.x);
}
double Andrew()
{
sort(p+,p+n+,cmp);
int cnt=,tot=;
double sum=0.0;
for(int i=;i<=n;i++)
{
s[++cnt]=p[i];
while(cnt>=&&getk(s[cnt-],s[cnt])<getk(s[cnt-],s[cnt-]))
s[cnt-]=s[cnt],cnt--;
}
for(int i=;i<=cnt-;i++)
sum+=dis(s[i],s[i+]);
tot=cnt;
cnt=;
for(int i=n;i>=;i--)
{
s[++cnt]=p[i];
while(cnt>=&&getk(s[cnt-],s[cnt])<getk(s[cnt-],s[cnt-]))
s[cnt-]=s[cnt],cnt--;
}
for(int i=;i<=cnt-;i++)
sum+=dis(s[i],s[i+]);
tot+=cnt;
tot-=;//tot是凸包上点的个数
//printf("%d\n",tot);
return sum;
}
int main()
{
//freopen("fc.in","r",stdin);
//freopen("fc.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%lf %lf",&p[i].x,&p[i].y);
printf("%.2lf\n",Andrew());
return ;
}

Code

还有一个用叉积写的,原理都是一样的, 不过我自己不是很喜欢这种写法:

 /*
ID: Starry21
LANG: C++
TASK: shuttle
*/
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define N 10005
struct node{
double x,y;
};
node p[N],s[N]/*凸包上的点*/;
int n;
double dis(node a,node b)
{
return sqrt(((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)));
}
bool cmp(node a,node b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool Cross(node a,node b,node c)
{
double x1=a.x-b.x,y1=a.y-b.y;
double x2=c.x-b.x,y2=c.y-b.y;
if((x1*y2-x2*y1)<=) return ;
//如果不希望在凸包的边上有输入点。把<=改成<
return ;
}
int Andrew()
{
sort(p+,p+n+,cmp);
int num=;
for(int i=;i<=n;i++)
{
while(num>&&!Cross(s[num-],s[num-],p[i]))
num--;
s[num++]=p[i];
}
int tmp=num;
for(int i=n-;i>=;i--)
{
while(num>tmp&&!Cross(s[num-],s[num-],p[i]))
num--;
s[num++]=p[i];
}
if(n>) num--;
return num;
}
int main()
{
//freopen("shuttle.in","r",stdin);
//freopen("shuttle.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%lf %lf",&p[i].x,&p[i].y);
int num=Andrew();
double sum=;
for(int i=;i<=num-;i++)
sum+=dis(s[i],s[i+]);
sum+=dis(s[num],s[]);//还有第n个点到第1个点的距离
printf("%.2lf",sum);
return ;
}

Code

Andrew算法求二维凸包-学习笔记的更多相关文章

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

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

  2. python生成个性二维码学习笔记

    在linux环境下进行编码 1.先进家目录,自行创建Code文件夹 cd Code 2.下载MyQR库 sudo pip3 install MyQR 3.下载所需资源文件并解压 Code/ $ wge ...

  3. GiftWrapping算法解决二维凸包问题

    一.问题描述 凸集(Convex Set): 任意两点的连线都在这个集合内的集合就是一个凸集.             ⒈对于一个集合D,D中任意有限个点的线性组合的全体称为D的凸包.         ...

  4. Codeforces Gym 100286A. Aerodynamics 计算几何 求二维凸包面积

    Problem A. AerodynamicsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/co ...

  5. java生成二维码学习笔记

    纠错等级: QRErrorCorrectLevel.L 7%的字码可被修正 QRErrorCorrectLevel.M 15%的字码可被修正 QRErrorCorrectLevel.Q 25%的字码可 ...

  6. 计算几何 二维凸包问题 Andrew算法

    凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...

  7. Luogu P2742 模板-二维凸包

    Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...

  8. 【计算几何】二维凸包——Graham's Scan法

    凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...

  9. poj 2079 Triangle (二维凸包旋转卡壳)

    Triangle Time Limit: 3000MS   Memory Limit: 30000KB   64bit IO Format: %I64d & %I64u Submit Stat ...

随机推荐

  1. 特征工程之分箱--Best-KS分箱

    变量的KS值 KS(Kolmogorov-Smirnov)用于模型风险区分能力进行评估,指标衡量的是好坏样本累计部分之间的差距 .KS值越大,表示该变量越能将正,负客户的区分程度越大.通常来说,KS& ...

  2. 【C#-多线程】实现每隔一段时间执行代码(多线程) 3种定时器

    总结以下三种方法,实现c#每隔一段时间执行代码: 方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间: 方法二:使用System.Timers.Timer类: 方法三:使用Sys ...

  3. JavaScript基础之变量的自增与自减

    一.自增(++) ⑴什么是自增? 通过自增运算符可以使变量在自身的基础上加一: 对于一个变量自增以后,原变量的值会立即自增一: 示例: <!DOCTYPE html> <html l ...

  4. maven项目创7 配置分页插件

    页面编写顺序   首先确定是否拥有想要的pojo(对象实体类)———>dao层mybatis配置——>service层的接口及实现类——>controller(web下) 分页插件作 ...

  5. HDU 5113 Black And White ( 2014 北京区预赛 B 、搜索 + 剪枝 )

    题目链接 题意 : 给出 n * m 的网格.要你用 k 种不同的颜色填给出的网格.使得相邻的格子颜色不同.若有解要输出具体的方案 分析 : 看似构造.实则搜索.手构构半天没有什么好想法 直接搜就行了 ...

  6. ACM-ICPC 2018 沈阳赛区网络预赛 I 题 Lattice's basics in digital electronics

    原题链接:https://nanti.jisuanke.com/t/31450 附上队友代码:(感谢队友带飞) #include <bits/stdc++.h> using namespa ...

  7. Codeforces Round #564 (Div. 1)

    Codeforces Round #564 (Div. 1) A Nauuo and Cards 首先如果牌库中最后的牌是\(1,2,\cdots, k\),那么就模拟一下能不能每次打出第\(k+i\ ...

  8. BOM基础笔记

    BOM基础 BOM对浏览器的一些操作 1.打开.关闭窗口 •open –蓝色理想运行代码功能 window.open('http://www.baidu.com/', '_self'); <!d ...

  9. HashMap在什么场景下会由哪些内部方法导致线程不安全,至少给出一种场景

    一直以来只是知道HashMap是线程不安全的,但是到底HashMap为什么线程不安全,多线程并发的时候在什么情况下可能出现问题? HashMap底层是一个Entry数组,当发生hash冲突的时候,ha ...

  10. Linux下MySQL报Table 'xxx' doesn't exist错误解决方法,表名存在大小写区分

    Linux服务器上在线装了个MySQL,但是部署web应用时一直报后台一直报错:Table 'xxx' doesn't exist. 本地测试一直都是正常的,同样的代码,同样的数据库,表是存在的,但是 ...