凸包总结

有关凸包的知识其实并不难理解,稍微看看便可以懂得凸包的流程与原理。

1.什么是凸包?

    在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。(来源于百度百科)

    通俗来说,凸包便是可以将平面内所有点都包括进去的凸多边形。放张图理解一下,图中红色边框框起来的便是一个凸包。

2.怎么实现?

   凸包的实现其实十分简单。先找出平面中最下面的点(即y坐标最下的点)u,这个点肯定在凸包上。再以这个点为极点进行极角排序。什么是极角排序呢,极角排序就是以点u为坐标原点,根据所有点与点u连成的直线与x轴正方向的夹角从小到大进行排序。极角排序后,将点u与夹角最小的点加入栈中,之后依次扫描每一个点,若这个点所处的位置在栈顶点的左边,则可以加入栈中,若在右边,就弹出栈首,如此扫描,最后凸包上的点就是栈中的元素。怎么判断扫描到的点在左边还是右边呢?这便要用到叉积的知识。设a(x1,y1),b(x2,y2),c(x3,y3),那么如果x1*y2+x2*y3+x3*y1>x1*y3+x2*y1+x3*y2,就可以说明点c在直线ab的右边(直线方向a->b)。

模板题:https://www.luogu.org/problemnew/show/P2742代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #define rint register int
 5 using namespace std;
 6 
 7 struct node{
 8     double x,y;
 9 }a[10001];
10 int n,p,st[10001],top;
11 double ans,miny=2e9,minx=2e9;
12 
13 int cmp(node b,node c) { //极角排序 
14     if (fabs((b.y-miny)*(c.x-minx)-(c.y-miny)*(b.x-minx))<=1e-8) return fabs(minx-b.x)<fabs(minx-c.x);
15     return (b.y-miny)*(c.x-minx)<(c.y-miny)*(b.x-minx);
16 }
17 
18 int check(int b,int c,int d) { //叉积判断 
19     return ((a[b].x*a[c].y)+(a[c].x*a[d].y)+(a[d].x*a[b].y)-(a[b].x*a[d].y)-(a[c].x*a[b].y)-(a[d].x*a[c].y))>0;
20 }
21 
22 double dist(double x1,double y1,double x2,double y2) { //计算两点间的欧几里得距离 
23     return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
24 }
25 
26 int main() {
27     rint i;
28     scanf("%d",&n);
29       for (i=1;i<=n;++i) {
30           scanf("%lf %lf",&a[i].x,&a[i].y);
31             if (a[i].y<miny) { //寻找最下方的点 
32                   miny=a[i].y; minx=a[i].x;
33               }
34       }
35     sort(a+1,a+1+n,cmp); //极角排序 
36     st[1]=1; st[2]=2; top=2; //将两个点加入栈中 
37       for (i=3;i<=n;++i) { //扫描 
38           while (!check(st[top-1],st[top],i)) top--;
39           st[++top]=i;
40       }
41       for (i=2;i<=top;++i) //计算答案 
42         ans+=dist(a[st[i-1]].x,a[st[i-1]].y,a[st[i]].x,a[st[i]].y);
43     ans+=dist(a[st[top]].x,a[st[top]].y,a[1].x,a[st[1]].y);
44     printf("%.2lf",ans);
45     return 0;
46 }
原文地址:https://www.cnblogs.com/Gaxc/p/9610900.html