8th 【计算几何】凸包
来源:互联网 发布:sql内连接的意义 编辑:程序博客网 时间:2024/06/14 08:46
凸包
【题目描述】:
平面上的N个点,求一个包含所有点的最小的凸多边形,这就是凸包问题了。这可以形象地想成这样:在地上放置一些不可移动的木桩,用一根绳子把他们尽量紧地圈起来,并且为凸边形,这就是凸包了。
【输入描述】:
第一行一个N,表示平面上的点数。
以下N行,每行一个x和y,表示一个点的横坐标和纵坐标。
【输出描述】:
输出最少的点形成的凸多边形,第一个点是y最小的点,如果y相同的点,x小的排在前面。
【样例输入】:
82720 -44346 -2422-2077 -13464520 -4963-1791 1547-1262 4025-2997 913-1667 -2499
【样例输出】:
4520 -49632720 -443-1262 4025-2997 913-1667 -2499
【时间限制、数据范围及描述】:
时间:1s 空间:128M
N<=100000 -10000<=x,y<=10000
所谓凸包,可想象为一条刚好包著所有点的橡皮圈。
因为不方便作图,我大致用文字叙述下方法。
首先找到一个最低偏左点,然后按照延此点的角度大小顺序开始扫描,如果该点不会影响凸性,就继续扫描,否则就把已经找到的最后一个点删去,然后在判断是否影响凸包的凸性。(这里的实现需要用栈)
那么如何判断该点是否可取呢,这就是叉积运用了,通过叉积判断某线段在已知线段的顺时针方向或是逆时针方向。
(这是计算几何的知识,可以参考网上一些关于叉积的详细描述)
关于极角排序,也是关于叉积的知识,按极角排序,如果极角相同,按距离小大排序。
凸包的具体过程可以参考下面过程(图很清楚)
原文链接:https://segmentfault.com/a/1190000000488339;作者: Michael_Lin
首先介绍一下二维向量的叉积(这里和真正的叉积还是不同的):对于二维向量a=(x1,y2)和b=(x2,y2),a×b定义为x1*y2-y1*x2。而它的几何意义就是|a||b|sin<a,b>。如果a与b夹角小于180度(逆时针),那么这个值就是正值,大于180度就是负值。需要注意的是,左乘和右乘是不同的。如图所示:
Graham Scan算法的做法是先定下一个起点,一般是最左边的点和最右边的点,然后一个个点扫过去,如果新加入的点和之前已经找到的点所构成的“壳”凸性没有变化,就继续扫,否则就把已经找到的最后一个点删去,再比较凸性,直到凸性不发生变化。分别扫描上下两个“壳”,合并在一起,凸包就找到了。这么说很抽象,我们看图来解释:
我们找下“壳”,上下其实是一样的。首先加入两个点A和C:
然后插入第三个点G,并计算AC×CG的叉积,却发现叉积小于0,也就是说逆时针方向上∠ACG大于180度,于是删去C点,加入G点:
然后就是依照这个步骤便能加入D点。在AD上方是以D为起点。就能够找到AGD和DFEA两个凸壳。合并就得到了凸包。
上述过程是很清楚的,关于叉积如果有不理解的可以上网查一下,数学知识我就不解释了(呵呵主要是解释不好)
下面是我写的程序
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath>using namespace std; int n,top;struct node{ int x; int y; };node a[100005],ans[100005],start; // a为原数组,ans为栈,start为起点。 int chaji(node p1,node p2,node p0){return(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}//计算叉积 void findmin(){ start.x=2147483647; start.y=2147483647; for(int i=1;i<=n;i++) if((a[i].y<start.y)||(a[i].y==start.y&&a[i].x<start.x)) { start.x=a[i].x; start.y=a[i].y;} }//寻找最低偏左的点,就是起点。 int cmp(node a,node b){ if(chaji(a,b,start)==0) { int disa=(a.x-start.x)*(a.x-start.x)+(a.y-start.y)*(a.y-start.y); int disb=(b.x-start.x)*(b.x-start.x)+(b.y-start.y)*(b.y-start.y); return (disa<disb); } return (chaji(a,b,start)>0); } //极角排序,先按角度,后按距离 void tubao(){ //中心程序,从第三个点开始扫描 ans[1]=start; ans[2]=a[2]; top=2; for(int i=3;i<=n;i++) { while(chaji(a[i],ans[top],ans[top-1])>=0&&top>0)//判断该点是否改变凸包,如果可以就再往回走一个点,再判断 top--; ans[++top]=a[i]; //每次最终连接两点 } } int main() { freopen("test1.in","r",stdin); freopen("test1.out","w",stdout); //清晰的操作过程 cin>>n; for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;//读入 findmin();//寻找起点 sort(a+1,a+n+1,cmp); //排序 tubao();//扫描找凸包 for(int i=1;i<=top;i++) cout<<ans[i].x<<" "<<ans[i].y<<endl;//将栈里元素输出 return 0; }
- 8th 【计算几何】凸包
- 9th 【凸包&&计算几何】最远点对
- 计算几何-凸包
- [计算几何]凸包算法
- 计算几何之凸包
- 计算几何-凸包问题
- 计算几何 --- 凸包 模板
- 计算几何凸包详解
- 计算几何中的凸包计算
- 计算几何__凸包算法
- [计算几何]凸包算法 收藏
- [计算几何-凸包]pku1113-Wall
- 计算几何 Graham_scan凸包 pku 1113
- POJ 1113 WALL(凸包-计算几何)
- 计算几何__凸包算法
- poj 1113 计算几何 凸包
- 计算几何——凸包
- 计算几何-经典算法-凸包
- 大数阶乘(C语言实现)
- Spring、Spring MVC、MyBatis整合文件配置详解
- 被虐到死去活来的Mysql乱码问题
- 深入浅出JMS(四)--Spring和ActiveMQ整合的完整实例
- MySQL logrotate配置
- 8th 【计算几何】凸包
- crc 循环校验码
- Mybatis 基础教程之一--入门
- 送分题!考研数学压轴必考题型是......
- 闭包
- Andriod含跳转的简单计算器
- 浅谈Maven
- java常量池概念
- Spark缓存策略说明及选择