凸包与Andrew算法——学习笔记

来源:互联网 发布:java 小写字母转大写 编辑:程序博客网 时间:2024/06/13 05:23

凸包

已知一个点集,凸包就是指将这些些点全部包围在内部的,且面积最小的凸多边形。
举个例子
这里写图片描述

以下介绍一种解决凸包问题的算法Andrew算法。


Andrew算法

首先先把所有点排序(排序方法同前面定义<相同),必要时删除重复点,然后把点1和点2放入凸包的栈中,然后从p3开始当新的点在凸包前进的方向的左边时加入并继续,否则说明方向已经向内凹了,此时依次删除当时在栈顶的点,直至新点在左边。
依旧举栗子:
这里写图片描述
此时新点E方向在向量CD的右边,所以需要在凸包的栈中删除C和D,让B的下一个点为E,重复此过程,直至碰到最右边的pn,求出了凸包下部分,然后反过来求出凸包的上部分,合起来求得完整的凸包。
这里写图片描述
Andrew算法复杂度并不高,排序后处理就是线性的O(n),加上排序也只是O(nlogn)。
代码:

void Andrew(){  sort(a+1,a+n+1);  tot=0;  for (int i=1;i<=n;i++)  {    while (tot>1&&dcmp(cross(b[tot]-b[tot-1],a[i]-b[tot-1]))<0) tot--;    b[++tot]=a[i];  }  int k=tot;  for (int i=n-1;i>0;i--)  {    while (tot>k&&dcmp(cross(b[tot]-b[tot-1],a[i]-b[tot-1]))<0) tot--;    b[++tot]=a[i];  }  if (n>1) tot--;//由于第一个点会算两遍,所以最终凸包点个数要-1,但有一些求凸包周长的时候为了计算方便去掉这一行。}

模板:POJ 1113 说是凸包的边长加2*pi*r(r已给出),然而菜鸡fhj不会证明,若各位大佬知道请务必在评论区教教本菜鸡。

#include<cmath>#include<cstdio>#include<algorithm>using namespace std;int n,tot;double ans,R,eps=1e-5;struct data{  double x,y;  data (double x=0,double y=0):x(x),y(y){}  bool operator < (const data b) const{    return (x<b.x||(x==b.x&&y<b.y));  }}a[1005],b[1005];data operator - (const data a,const data b){return data(a.x-b.x,a.y-b.y);}double dot(const data a,const data b){return a.x*b.x+a.y*b.y;}double leng(const data x){return sqrt(dot(x,x));}double cross(const data a,const data b){return a.x*b.y-a.y*b.x;}int dcmp(double x){  if (fabs(x)<eps) return 0;  return (x<0)?-1:1;}void Andrew(){  sort(a+1,a+n+1);  tot=0;  for (int i=1;i<=n;i++)  {    while (tot>1&&dcmp(cross(b[tot]-b[tot-1],a[i]-b[tot-1]))<0) tot--;    b[++tot]=a[i];  }  int k=tot;  for (int i=n-1;i>0;i--)  {    while (tot>k&&dcmp(cross(b[tot]-b[tot-1],a[i]-b[tot-1]))<0) tot--;    b[++tot]=a[i];  }}int main(){  freopen("wall.in","r",stdin);  freopen("wall.out","w",stdout);  scanf("%d%lf",&n,&R);  for (int i=1;i<=n;i++)  {    double x,y; scanf("%lf%lf",&x,&y); a[i]=data(x,y);  }  Andrew(); ans=0.0;  for (int i=1;i<tot;i++) ans+=leng(b[i+1]-b[i]);  printf("%0.0lf",ans+2*R*3.14159);  return 0;}

PS:本博客比较简陋,加之作者fhj水平实在菜鸡,所以各位大佬请多多谅解,如有错误,请多多指出!
PPS:Orz zzk

阅读全文
0 0
原创粉丝点击