《算法导论》第33章 凸包问题

合集下载

凸包问题的分治算法

凸包问题的分治算法
CQUPT
凸包问题的分治算法
姓名:任小康,梅冬,连如鹤 学号:2011211706,2011211732,2011211707 学院:计算机学院 班级:0491102
凸包问题描述
凸包问题可以描述为:给定一个点集P,求最小点集S, 使得S构成的形状能包含P[1]。一般的研究主要针对二维平 面上和三维空间上的凸包,因为他们在更多的应用中能发挥 作用。 凸包的定义为:平面的一个子集S被称为是“凸”的, 当且进当对于任意两点p,q∈S,线段都完全属于S。几何S 的凸包CH(S),就是包含S的最小凸集,更准确地说,它是 包含S的所有凸集的交。由此还可以推出凸包的很多性质, 包括一条直线如果与凸包相交(不是相切)的话,最多交于 两条边或者两即为点集Q={p0,p1, p2,...,p11,p12}的凸包。
一组平面上的点,求一个包含所有点的最小凸边形,既 是凸包问题。 • 形象地说:在一平木板(平面)上钉若干钉子(点), 将一橡皮筋套上去后,会把钉子圈起来,形成一个凸边形, 即为该点集的凸包。


致谢《算法设计与分析基础》
感谢您的关注

分治法是一种很基础的算法。基本思路是将问题分解为 等价的几个子问题,对子问题进行递归分解和求解,然后将 子问题的解合成为所求的解。 由此,可以得到一种最简单的凸包分治算法:将点集依 照某种划分方法分为N部分,对每个部分求子凸包,最后将 几个子凸包合成一个更大的凸包。

请输入内容
• •
由此就可得到凸包问题的分治算法。 根据分治算法的思路,凸包问题的分支算法有着很好的 平均效率,一般会把问题平均分成为两个比较小的子问题, 这样会把效率提高很多。

凸包convexhullppt课件

凸包convexhullppt课件

Graham模版(水平序) by 吉林大学:
凸包问题:
凸包问题一般有以下两类: 1.求凸包面积周长 2.求平面最远点对
凸包面积周长 我们先来看一个问题,POJ 1113。 题意:有个贪心的国王叫他的建筑师给他的城堡周围建个围墙,他要求用最少的石
头和劳动力来建造,而且要在距离城堡某个距离L之外建造。 解法:
旋转卡壳的应用
旋转卡壳主要是用来求点集中最远点对的。如POJ 2187,就是一道求最远 点对的裸题。学会了旋转卡壳用模版可以直接过。具体参照code。
POJ 3608,求两个凸包间的最短距离。 个人解法:先求出两个凸包,然后对其中一个凸包的左下方的基准点,对
另外一个凸包求最小对应边。然后再从另外一个凸包的左下方的基准点,对前个凸
怎么从给定的点中找凸包呢?
1.卷包裹算法
2. Graham扫描算法
卷包裹算法
可以说是一个很朴素的算法,其时间复杂度最坏情况为O(n^2),其实现原理非常简 单。就像是拿了一根绳子,以最左下方的点开始,围着所有点的外围围了一圈。
先找到横坐标最小的点中纵坐标最小的点,然后以该点作为基准点,对剩余的所有
旋转卡壳算法: 这是一个非常优美而高效的算法(演示图如下):
旋转卡壳算法是解决一些与凸包有关问题的有效算法 就像一对卡壳卡住凸包 旋转而得名。被一对卡壳正好卡住的对应点对称为对踵点(Antipodal point),可以证明对 踵点的个数不超过3N/2个 也就是说对踵点的个数是O(N)的,对踵点的个数也是解决问 题的时间复杂度的保证。
while(fabs(cross(res[p+1],res[p],res[q+1]))>fabs(cross(res[p+1],res[p],res[q]))) q=(q+1)%n;

凸包算法

凸包算法

长 江 大 学 地 球 科 学 学 院
遗留有一个问题 就是处理共线的问题 有时候我们需要凸包边上的点也考虑到 有时候却需要去掉这些点 我们通常称在凸包顶点处的点为极点 如果我们只要求保留极点而去除在边上的点 我们只需在取外侧的点的时候 碰到共线的点取最远的 相反 如果我们要保留所有在边上的点我们只需要在共线的点中取最近的 同样由于参考点的性质 所有向量之间的到角都是在180度以内 不会产生错误
我们经常关注一个点集的凸包 这也是计算几何学的一个基本问题,现在 已经有成熟的算法可以求出平面点集的凸包,凸包有着优美而实用的 性质 我们可以利用凸包把一个杂乱的点集所包含的信息进行有效的 概括、梳理。
2 Graham扫描算法(Graham Scan Algorithm)
Graham扫描算法维护一个凸壳 通过不断在凸壳中加入新的点和去除影响 凸性的点 最后形成凸包 算法主体由两部分组成 先是排序 后是扫描 分块讲解一下
void Graham(int n) { int i,top=2; Pt[n]=Pt[0]; Stack[0]=Pt[0]; Stack[1]=Pt[1]; Stack[2]=Pt[2]; for(i=3;i<=n;i++) { while(Cross(Stack[top1],Stack[top],Pt[i])<=0&&top>1) top--; Stack[++top]=Pt[i]; } }
有了向量 我们就可以选取一个最外侧的点了
长 江 大 学 地 球 科 学 学 院
利用向量 我们可以比较哪个点"更外侧" 比如点K和点I 我们利用向量JK乘以向量JI得到一个数 这 个数应该是负数 说明I比K更外侧 两个向量的比较具有传递性 所以我们可以像N个数里取 最大的数一样取出最外侧的 遍历所有点 每个点都和现有最外侧的点比较 得到新的最 外侧的点

凸包——精选推荐

凸包——精选推荐

凸包算法模型想象在⼀个平⾯上钉下了n个钉⼦。

现在有⼀根橡⽪筋,我们把它撑开,期望在松⼿之后橡⽪筋可以收缩,包住所有的n个钉⼦。

事实上,这正是⼀个凸包。

如下图:引⼊凸包的概念:凸包,定义为周长最⼩的包含点集中所有点的凸多边形。

即使存在某个凹多边形的周长与凸包相等且可以包含所有点,这个凹多边形也⼀定不是凸包。

如下图,这个凹多边形不是该点集的凸包:凸包问题属于计算⼏何,通常可以使⽤Andrew,Graham,Jarvis,斜率逼近等算法求解。

本⽂将着重介绍其中思想通俗、代码简单的Andrew算法。

由于求解凸包需要⼀些前置的计算⼏何知识,本⽂将会介绍⼀些基础计算⼏何知识。

前置知识引进向量的概念。

在数学中,向量指同时具有⼤⼩和⽅向的量,与之相对的量称为数量。

数量只有⼤⼩,没有⽅向。

向量可以⽤⼀条带箭头的线段来形象地表⽰:箭头代表⽅向,线段的长度代表向量的⼤⼩。

如果向量的起点为A,终点为B,则这个向量可以记作→ab。

两个向量→x1,y1和→x2,y2的外积称之为叉积,它的结果是⼀个向量。

叉积的计算⽅法是 (x1y2)−(x2y1) ,记为→x1,y1×→x2,y2。

对于两个向量→ab,→bc,如果它们的叉积>0 ,说明→ab在→bc的顺时针⽅向;如果它们的叉积=0,说明→ab和→bc共线;如果它们的叉积<0,说明→ab在→bc的逆时针⽅向。

算法思想凸包Andrew算法的思想⾮常简单。

我们⾸先把点集按照以x坐标为第⼀关键字,以y坐标为第⼆关键字的⽅式进⾏双关键字从⼩到⼤排序,排序后的第⼀个点就是我们选出的极点。

两个关键字的顺序可以调换。

如下图,点 1 就是该点集的极点。

接着,我们从极点开始逆时针考虑将每⼀个点都加⼊凸包。

显然我们排序后的第⼀个点和最后⼀个点⼀定在凸包上。

从第⼆个点开始,我们假设当前点可以加⼊凸包。

设凸包上此时有m个点,第m−1 个点和第m个点分别是a,b,当前要加⼊凸包的点为c。

【算法】凸包问题--分治法

【算法】凸包问题--分治法

【算法】凸包问题--分治法凸包问题--分治法求能够完全包含平⾯上n个给定点的凸多边形。

⽰例:⼀、分治法:(⼀)算法思路:(这⾥所说的直线都是有向直线的。

)将数组升序排序,若x轴坐标相同,按照y轴坐标升序排序。

最左边的点p1和最右边的点p_n⼀定是该集合凸包的顶点。

该直线将点分为两个集合,上包为S1,下包为S2。

在p1 p_n线上的点不可能是凸包的顶点,所以不⽤考虑。

在上包S1中,找到p_max(距离直线p1p_n最远距离的点),若有两个距离同样远的点,取∠p_max p1 p_n最⼤的那个点(即△p_max p1 p_n⾯积最⼤)。

(⼀次递归到这⾥结束)找出S1中所有在直线p1 p_max左边的点,这些点中⼀定有构成上包中左半部分边界的顶点,⽤上⾯的算法递归查找点,直到上包就是以p1和p_n 为端点的线段。

下包S2中找下边界同理。

*如何判断点是否在直线p1 p_max左边(同 p1 p_n上⽅)?如果q1(x1,y1),q2(x2,y2),q3(x3,y3)是平⾯上的任意三个点,那么三⾓形△q1 q2 q3的⾯积等于下⾯这个⾏列式绝对值的⼆分之⼀。

当且仅当点q3=(x3,y3)位于直线q1 q2的左侧时,该表达式的符号为正,该点位于两个点确定的直线的左侧。

(⼆)实现中碰到的问题如何⽤快速排序来排序Point类(内有坐标x,y)的⼀维数组?按照x坐标排序很简单,若碰到x相同,y不同的怎么办?在快排的原基础上修改,以j向前逼近说明:(第⼀个while循环)当前⽐较数的横坐标>基准点的时,j向前逼近。

此处不加等于号,排序是不稳定的,即相等元素的相对位置可能发⽣改变。

(快排详见博客:(第⼆个while为添加内容)⽐较相等元素的纵坐标,基准点的更⼩,j继续向前逼近,即相等元素的相对位置不发⽣改变;否则,则改变。

也就是将原来快排中while循环拆分为两个,增加相等元素另外⽐较纵坐标的情况。

while (i < j && points[j].getX() > center.getX()) {j--;}while (i < j && center.getX() == points[j].getX() && points[j].getY() > center.getY()) {j--;}/** (i<j)若points[j].getX()< center.getX()或 center.getX() ==* points[j].getX()且points[j].getY()<center.getY() 以上两种情况,需要赋值*/if (i < j)// 跳出循环也有可能时因为i=j,所以这⾥要判断⼀下points[i++] = points[j];如果使⽤全局数组visit标识点是否访问,能确定凸包的所有顶点,但怎么顺序输出?在已经求的凸包顶点⾥逐⼀确定边界,判断是不是所有点都在这条边界的⼀侧,如果是则确定⼀条边界。

文档:凸包问题-graham扫描

文档:凸包问题-graham扫描

凸包问题-graham扫描{graham扫描法通过设置一个关于后选点的堆栈s来解决凸包问题。

输入集合Q中的每个点都被压入栈一次,非ch(Q)中的顶点的点最终会被弹出堆栈。

当算法终止时,堆栈s中仅包含ch(Q)中的顶点,其顺序为各点在边界上出现的逆时针方向排列的顺序。

过程graham_scan的输入点集Q,它调用函数top(s),以便在不改变堆栈s的情况下,返回处于栈顶的点,并调用函数next_to_top(s),来返回处于堆栈顶部下面的那个点,切不改变栈s。

} {graham_scan寻找凸报,时间复杂度为O(nlgn),但我用的选择排序,所以成O(n2)的了1、let p0 be the point in Q with the minimum y-coordinate,or the leftmost such point in case of a tie2、let<p1,p2,p3...pm>be the remaining points in Q,sorted by polar angle in counterclockwise order around p0(if more than one point has the same angle,remove all butthe one that is farthest from p03、push(p0,s)4、push(p1,s)5、push(p2,s)6、for i:=3 to m dowhile the angle formed by points next-to-top(s),top(s),and(pi) makes a nonleft trun8、do pop(s)9、push(pi,s),10、retur s}{copyright 陈舒伟,对已知的一些点寻找凸包}program xxxxxx;consteps=1e-6;typetpoint=record//点类型x,y:longint;end;varq:array[1..1000]of tpoint;//初始点级ch:array[1..1000]of tpoint;//最后寸凸包的点的数组qq:array[1..1000]of tpoint;//排序后的点集;co:array[1..1000]of double;//初始coscoo:array[1..1000]of double;//排序后的cosd:array[1..1000]of double;//r,计算cos用x/rdd:array[1..1000]of double;//排序后的rn,tail:longint;procedure find_min_y;{找出y坐标最小点}vari,j:longint;t:tpoint;beginfor i:=2 to n doif (q[1].y>q[i].y)or((q[1].y=q[i].y)and(q[1].x>q[i].x)) thenbegint:=q[1];q[1]:=q[i];q[i]:=t;end;end;procedure cal_cos;//计算点到定点的cos极角;vari:longint;x,y:longint;beginfor i:=2 to n dobeginx:=q[i].x-q[1].x;y:=q[i].y-q[1].y;d[i]:=sqrt(x*x+y*y);co[i]:=x/d[i];end;end;function same(a,b:double):boolean;beginsame:=abs(a-b)<eps;end;procedure sort_and_ok;{根据极角从小到大排序,如果有相同极角的只取最外面的一个}vari,j:longint;x:double;t:tpoint;tt:double;beginfor i:=2 to n-1 dofor j:=i+1 to n doif (co[j]-co[j]>eps)or((same(co[i],co[j]))and(d[i]>d[j])) then begint:=q[i];q[i]:=q[j];q[j]:=t;x:=co[i];co[i]:=co[j];co[j]:=x;tt:=d[i];d[i]:=d[j];d[j]:=tt;end;qq:=q;coo:=co;dd:=d;tail:=n;end;procedure init;//初始化,读数vari:longint;beginread(n);for i:=1 to n doread(q[i].x,q[i].y);find_min_y;//找出凸包的第一个点,y坐标最小点,如果有多个最小,取最左边的;cal_cos;//计算每个点到顶点的cossort_and_ok;//根据cos的值,可以根据极角从小到大排序;end;function area2(pa,pb,pc:tpoint):double;{判断是否符合凸包条件,向量都是向左转,逆时针方向的}beginarea2:=(pb.x-pa.x)*(pc.y-pa.y)-(pc.x-pa.x)*(pb.y-pa.y);end;procedure build;//构建凸包的过程vari,j,k:longint;beginch[1]:=qq[1];ch[2]:=qq[2];ch[3]:=qq[3];//初始化,栈中存三个点j:=3;for i:=4 to tail do//依次扫描后面的点,选取新的点构建凸包beginif area2(ch[j-1],ch[j],qq[i])<0 then//如果新的点又向量右转得到begin//那么肯定不是凸包,对原来的进行一次调整ch[j]:=qq[i];k:=j-1;while area2(ch[k-1],ch[k],ch[j])<0 dobegindec(j);ch[j]:=qq[i];k:=j-1;end;endelse begininc(j);ch[j]:=qq[i];end;end;for i:=1 to j dowriteln(ch[i].x,' ',ch[i].y);end;beginassign(input,'a.in');assign(output,'a.out');reset(input);rewrite(output);init;build;close(output);end.。

凸包

凸包
凸包问题分治法求解
凸包问题实例——果园篱笆
问题描述:
某大学ACM集训队,不久前向学校申请了一块空地,成为自己的果 园。全体队员兴高采烈的策划方案,种植了大批果树,有梨树、桃树、 香蕉……。后来,发现有些坏蛋,他们暗地里偷摘果园的果子,被ACM 集训队队员们发现了。因此,大家商量解决办法,有人提出:修筑一 圈篱笆,把果园围起来,但是由于我们的经费有限,必须尽量节省资 金,所以,我们要找出一种最合理的方案。由于每道篱笆,无论长度 多少,都是同等价钱。所以,大家希望设计出来的修筑一圈篱笆的方 案所花费的资金最少。有人已经做了准备工作,统计了果园里所有果 树的位置,每棵果树分别用二维坐标来表示,进行定位。现在,他们 要求全体队员,每人给出一个最合理的方案,来解决修筑篱笆所遇到 的困难。要求根据所有的果树的位置,找出一个n边形的最小篱笆,使 得所有果树都包围在篱笆内部,或者在篱笆边沿上。
凸包问题的分治法
分治法:所谓分治法就是把问题划分成多个子问题来进 行处理。这些子问题,在结构上与原来的问题一样,但 在规模上比原来的小。如果得到的子问题相对来说还大, 可以反复地使用分治策略,把这些子问题再划分成更小 的、结构相同的子问题。这样就可以使用递归的方法, 分别求解这些子问题,把这些子问题的解结合起来,从 而获得原来问题的解。
凸包问题的分治解法
第三步:递归求解得到凸多边形的边。 第四步:合并这些边即得所求凸包。
凸包问题的分治法
算法复杂性:利用分治法考虑凸包问题, 关键步骤是点集按横坐标排序,算法复杂 性是(n log n) 。故凸包问题的分治法的算法 复杂性是(n log n) 。
凸包问题的分治解法
第一步:把给定点集中的点在横坐标方向上按照 大小排序。如下图பைடு நூலகம்示,P1 和 Pn 必定是凸多边形 的两个顶点。

关于凸包问题

关于凸包问题

关于凸包问题Graham扫描法基本思想:通过设置⼀个关于候选点的堆栈s来解决凸包问题。

操作:输⼊集合Q中的每⼀个点都被压⼊栈⼀次,⾮CH(Q)(表⽰Q的凸包)中的顶点的点最终将被弹出堆栈,当算法终⽌时,堆栈S中仅包含CH(Q)中的顶点,其顺序为个各顶点在边界上出现的逆时针⽅向排列的顺序。

注:下列过程要求|Q|>=3,它调⽤函数TOP(S)返回处于堆栈S 顶部的点,并调⽤函数NEXT-TO –TOP(S)返回处于堆栈顶部下⾯的那个点。

但不改变堆栈的结构。

GRAHAM-SCAN(Q)1 设P0 是Q 中Y 坐标最⼩的点,如果有多个这样的点则取最左边的点作为P0;2 设<P1,P2,……,Pm>是Q 中剩余的点,对其按逆时针⽅向相对P0 的极⾓进⾏排序,如果有数个点有相同的极⾓,则去掉其余的点,只留下⼀个与P0 距离最远的那个点;3 PUSH(p0 , S)4 PUSH(p1 , S)5 PUSH(p3 , S)6 for i ← 3 to m7 do while 由点NEXT-TOP-TOP(S),TOP(S)和Pi 所形成的⾓形成⼀次⾮左转8 do POP(S)9 PUSH(pi , S)10 return S⾸先,找⼀个凸包上的点,把这个点放到第⼀个点的位置P0。

然后把P1~Pm 按照P0Pi的⽅向排序,可以⽤⽮量积(叉积)判定。

做好了预处理后开始对堆栈中的点<p3,p4,...,pm>中的每⼀个点进⾏迭代,在第7到8⾏的while循环把发现不是凸包中的顶点的点从堆栈中移去。

(原理:沿逆时针⽅向通过凸包时,在每个顶点处应该向左转。

因此,while循环每次发现在⼀个顶点处没有向左转时,就把该顶点从堆栈中弹出。

)当算法向点pi推进、在已经弹出所有⾮左转的顶点后,就把pi压⼊堆栈中。

举例如下: ⽮量的概念: 如果⼀条线段的端点是有次序之分的,我们把这种线段成为有向线段(directed segment)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

《算法导论》第33章凸包问题
目录
1.凸包问题的定义和背景
2.凸包问题的应用
3.凸包问题的解决方案
4.凸包问题的算法分析
5.凸包问题的实际应用案例
正文
一、凸包问题的定义和背景
凸包问题是计算机图形学和计算几何中的一个经典问题。

它指的是给定一组二维或三维空间中的点,寻找一个最小的凸多边形,使得这个多边形包含了所有的点。

也就是说,任意一个点只要在凸包内部,就能被凸包上的某一点所见到,反之则不能。

二、凸包问题的应用
凸包问题在计算机图形学和计算几何中有广泛的应用,例如:
1.几何优化:通过凸包可以得到一组点的最小包围,可以应用于几何形状的优化和压缩。

2.碰撞检测:在计算机图形学中,凸包可以用于检测物体的碰撞,只要两个物体的凸包有交集,就说明两个物体发生了碰撞。

3.可视化:在数据可视化中,凸包可以帮助我们快速找到一组数据的主要分布区域。

三、凸包问题的解决方案
凸包问题的解决方案主要有以下几种:
1.基于三角剖分的方法:该方法通过将凸包分解成若干个三角形,然后利用三角形的性质来求解凸包。

2.基于团问题的方法:该方法将凸包问题转化为求解团问题,然后再将团问题转化为组合优化问题进行求解。

3.基于 Graham 扫描的方法:该方法是一种基于扫描线的方法,通过扫描线逐点扫描点集,可以快速得到凸包。

四、凸包问题的算法分析
以上三种方法都有对应的时间复杂度和空间复杂度。

例如,基于三角剖分的方法的时间复杂度为 O(nlogn),空间复杂度为 O(n);基于团问题的方法的时间复杂度为 O(n),空间复杂度为 O(n);基于 Graham 扫描的方法的时间复杂度为 O(n),空间复杂度为 O(1)。

五、凸包问题的实际应用案例
以碰撞检测为例,假设我们有两个物体 A 和 B,每个物体由多个点组成。

我们可以通过计算物体 A 和 B 的凸包,然后检测两个凸包是否有交集,如果有,就说明两个物体发生了碰撞。

相关文档
最新文档