Andrew算法求二维凸包-学习笔记
凸包的概念
首先,引入凸包的概念:

(有点窄的时候...图片右边可能会被吞,拉开图片看就可以了)
大概长这个样子:

那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包)
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算法求二维凸包-学习笔记的更多相关文章
- 使用Graham扫描法求二维凸包的一个程序
#include <iostream> #include <cstring> #include <cstdlib> #include <cmath> # ...
- python生成个性二维码学习笔记
在linux环境下进行编码 1.先进家目录,自行创建Code文件夹 cd Code 2.下载MyQR库 sudo pip3 install MyQR 3.下载所需资源文件并解压 Code/ $ wge ...
- GiftWrapping算法解决二维凸包问题
一.问题描述 凸集(Convex Set): 任意两点的连线都在这个集合内的集合就是一个凸集. ⒈对于一个集合D,D中任意有限个点的线性组合的全体称为D的凸包. ...
- Codeforces Gym 100286A. Aerodynamics 计算几何 求二维凸包面积
Problem A. AerodynamicsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/co ...
- java生成二维码学习笔记
纠错等级: QRErrorCorrectLevel.L 7%的字码可被修正 QRErrorCorrectLevel.M 15%的字码可被修正 QRErrorCorrectLevel.Q 25%的字码可 ...
- 计算几何 二维凸包问题 Andrew算法
凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...
- Luogu P2742 模板-二维凸包
Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...
- 【计算几何】二维凸包——Graham's Scan法
凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...
- poj 2079 Triangle (二维凸包旋转卡壳)
Triangle Time Limit: 3000MS Memory Limit: 30000KB 64bit IO Format: %I64d & %I64u Submit Stat ...
随机推荐
- 一例jsonp跨域访问
对于网站A,有一链接 '/auth/list',返回json数据 {, , , , , },{, , , , , }]} 网站b某页面下可以这样写jsonp get请求 <script> ...
- (转载) Consul 使用手册(感觉比较全了)
使用consul 介绍 Consul包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具.他提供以下关键特性: 服务发现 Consul的客户端可用提供一个服务,比如 api 或者 ...
- ajax上传文件(javaweb)
前台:FormData, formData.append("fileName",$("#file")[0].files[0];); https://ww ...
- 数据库连接windows身份验证、sql验证
windows身份验证:"server=.;database=Northwind;Integrated Security=True;" sql验证:"server=.;d ...
- 推荐系统系列(五):Deep Crossing理论与实践
背景 特征工程是绕不开的话题,巧妙的特征组合也许能够为模型带来质的提升.但同时,特征工程耗费的资源也是相当可观的,对于后期模型特征的维护.模型线上部署不太友好.2016年,微软提出Deep Cross ...
- *CodeIgniter框架集成支付宝即时到账SDK
客户的网站需要支付功能,我们选择了业界用的最多的支付宝即时到账支付.申请了两次将近两周的时间终于下来了,于是我开始着手测试SDK整合支付流程. SDK中的代码并不复杂,就是构造请求发送,接收并验证签名 ...
- Cannot use unsafe construct in safe context
https://stackoverflow.com/questions/25953887/how-to-use-unsafe-code-in-safe-contex I am not sure if ...
- grep命令和tail命令
写在前面的话: 最近参与了新项目开发,周期短,与自己负责的主要业务对接.业务复杂,时常出现bug,然额对于菜鸟的我,更是无从下手.其实最好的帮助就是 学会查看日志,关键是之前查看日志真是太少了,菜鸟一 ...
- 浅析history hack、心血漏洞、CSS欺骗、SQL注入与CSRF攻击
漏洞产生的原因主要有系统机制和编码规范两方面,由于网络协议的开放性,目前以 Web 漏洞居多 关于系统机制漏洞的典型有JavaScript/CSS history hack,而编码规范方面的漏洞典型有 ...
- Example Bookstore schema showing how data is sharded DATABASE SHARDING
w公共查询表复制至每一个碎片 http://www.agildata.com/database-sharding/ In the Bookstore example, the Primary Shar ...