zoukankan      html  css  js  c++  java
  • 计算几何之凸包

    凸包:把给定点包围在内部的、面积最小的凸多边形。

    Andrew算法是Graham算法的变种,速度更快稳定性也更好。

    首先把所有点排序,按照第一关键字x第二关键字y从小到大排序,删除重复点后得到点序列P1...Pn。

    1)把P1,P2放入凸包中,凸包中的点使用栈存储

    2)从p3开始,当下一个点在凸包当前前进方向(即直线p1p2)左边的时候继续;

    3)否则依次删除最近加入凸包的点,直到新点在左边。

    如图,新点P18在当前前进方向P10P15的右边(使用叉积判断),因此需要从凸包上删除点P15和P10,让P8的下一个点为P18。重复该过程直到碰到最右边的Pn,求出下凸包即凸包的下轮廓。然后从Pn反过来重复该步骤求出上凸包,合并起来后就是完整的凸包。

    该算法扫描为O(n)复杂度,排序O(nlogn)。

    具体可以参考刘汝佳的蓝书,有很好的讲解

    来一道模板题

     https://www.luogu.org/problemnew/show/P2742

    一波代码:

     1 #pragma GCC optimize(2)
     2 #include<cstdio>
     3 #include<vector>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define PI acos(double(-1))
     7 using namespace std;
     8 const int eps=1e-10;
     9 struct sd{
    10     double x,y;
    11     sd(){};
    12     sd (double a,double b) {x=a,y=b;}
    13     sd operator -(const sd v)const{return sd(x-v.x,y-v.y);}
    14 }map[100005],stackk[100005];
    15 int n;
    16 double dis(sd a,sd b)
    17 {
    18     return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)*1.0);
    19 }
    20 bool cmp(sd a,sd b)
    21 {
    22     if(a.x==b.x)
    23     return a.y<b.y;
    24     return a.x<b.x;
    25 }
    26 double fuck(sd a,sd b)
    27 {
    28     double ans=atan2((b.y-a.y),(b.x-a.x));
    29     if(ans<-PI/2) ans=ans+PI*2;
    30     return ans;
    31 }
    32 double cross(sd a,sd b)
    33 {
    34     return a.x*b.y-b.x*a.y;
    35 }
    36 int build()
    37 {
    38     int top=0;
    39     sort(map,map+n,cmp);
    40     for(int i=0;i<n;i++)
    41     {
    42         while(top>1&&cross(stackk[top-1]-stackk[top-2],map[i]-stackk[top-2])<=0) top--;
    43         stackk[top++]=map[i];
    44     }
    45     int k=top;
    46     for(int i=n-2;i>=0;i--)
    47     {
    48         while(top>k&&cross(stackk[top-1]-stackk[top-2],map[i]-stackk[top-2])<=0) top--;
    49         stackk[top++]=map[i];
    50     }
    51     if(n>1) top--;
    52     return top;
    53 }
    54 int main()
    55 {
    56     scanf("%d",&n);
    57     for(int i=0;i<n;i++)
    58     scanf("%lf%lf",&map[i].x,&map[i].y);
    59     int top=build();
    60     double ans=0;
    61     for(int i=1;i<top;i++)
    62     ans+=dis(stackk[i],stackk[i+1]);
    63     ans+=dis(stackk[top],stackk[1]);
    64     printf("%.2lf",ans);
    65     return 0;
    66 }
  • 相关阅读:
    手把手教你使用Python生成图灵智能小伙伴,实现工作助手/闲聊功能
    键盘侠Linux教程 | Linux运维工程师
    键盘侠Linux干货| ELK(Elasticsearch + Logstash + Kibana) 搭建教程
    键盘侠Linux教程(六)| 正则表达式与通配符
    键盘侠Linux干货| 使用SSH方式推送文件至github仓库
    键盘侠Linux干货| 使用Nginx创建一个私人网盘
    键盘侠Linux教程(五)| 基本权限管理
    键盘侠Linux教程(四)| 常用命令
    键盘侠Linux教程(一)|初学者建议
    键盘侠Linux教程(三)| Linux安装
  • 原文地址:https://www.cnblogs.com/genius777/p/8470594.html
Copyright © 2011-2022 走看看