凸包


这可能(一定)是我上高中之前的最后一篇博文了!

今天闲的没事(其实我有一堆作业没写完)听膜你抄(点击进入),莫名其妙看到了凸包,于是就在百度里输入了这俩字,于是看到了黄学长的文章,于是来到了博客园发了个这个玩意儿

正题:

1.什么是凸包?
(这里说平面凸包)凸包就是平面上有一些点,你要求出一个封闭图形使所有的点在这个封闭图形内,且这个图形的面积最小,且这个图形内的任意两点的连线不与封闭图形相交(我是这么理解的,说白了就是地上钉着一堆钉子,你有一个皮筋,要把这些钉子围起来,假设一开始皮筋是无限大的圆,所有钉子都在这里面,你一松手皮筋由于弹力开始收缩,最后皮筋会被钉子挡住(假设钉子无比坚硬),那么皮筋形成的图形就是凸包当我没说)
下面的图片来自维基百科,我们假设黑色的线是皮筋,毫无疑问松手之后他就变成了蓝色的线。蓝色的线就是这些点的凸包

“在二维欧几里得空间中,凸包可想象为一条刚好包着所有点的橡皮圈。”——维基百科(强悍!一句话解释)

2.算法 (时间复杂度坠高的算法)(一种奇怪的方法)
i我们首先要建立坐标系(废话),每个点都有其坐标。(输入数据) O(n)
ii选取纵坐标最小的点,如果有多个点则选取横坐标最小的点。 O(n)
iii求出每个点与这个点的连线和x轴夹角的角度 O(n)
iiii按照角度由小到大排序  O(nlog2n)//我们排序的目的是为了找连线与x轴夹角最小的点,所以只需遍历每个点更新即可,O(n)
iiiii找角度最小的点,把当前点和该点连线加入凸包 O(1)
iiiiii把上一步搜索到的最小的点当做当前的点,从步骤iii重复,直到求到ii找到的点为止。
时间复杂度O(nm)【m是凸包上点的个数,显然凸包上点越少越好】,最差O(n2)【所有点都在凸包上,重复n次】,最好O(n)【你说呢(滑稽)】

这种算法应该叫j什么什么s步进法,因为是依次找每个在凸包上的点。

代码 代更

3.g什么什么m扫描法(O(nlogn))

代更

然后呢这是洛谷板子题(USACO圈奶牛)的代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct vesor
{
    double x,y,p;
    vesor(double x=0,double y=0):x(x),y(y){}
    friend vesor operator-(const vesor&a,const vesor&b){return vesor(a.x-b.x,a.y-b.y);}
    friend double operator^(const vesor&a,const vesor&b){return a.x*b.y-a.y*b.x;}
    double mod(){return sqrt(x*x+y*y);}
}a[10010];
bool youngsc(const vesor&a,const vesor&b){return a.p<b.p;}
bool vis[10010];
int s[10010],top;
int minj=1,n;
double ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&a[i].x,&a[i].y);
        if(a[minj].y>a[i].y||(a[minj].y==a[i].y&&a[minj].x>a[i].x))
        {
            minj=i;
        }
    }
    swap(a[1],a[minj]);
    for(int i=2;i<=n;i++)
    {
        a[i].x-=a[1].x;
        a[i].y-=a[1].y;
        a[i].p=atan2(a[i].y,a[i].x);
    }
    sort(a+2,a+1+n,[](const vesor&a,const vesor&b){return a.p<b.p;});//lambda表达式编译错误 版本
    a[1].x=0;
    a[1].y=0;
    for(int i=1;i<=n;i++)
    {
//        printf("%f %f %f
",a[i].x,a[i].y,a[i].p);
    }
    s[1]=1;
    s[2]=2;
    s[3]=3;
    top=3;
    for(int i=4;i<=n;i++)//while(前前->前)在(前->cur)的逆时针,那前死
    {
        while(top>2&&((a[s[top]]-a[s[top-1]])^(a[i]-a[s[top]]))<0)
            top--;
        s[++top]=i;
    }
    for(int i=1;i<top;i++)
    {
//        printf("%d %d
",s[i],s[i+1]);
        ans+=(a[s[i+1]]-a[s[i]]).mod();
    }
    ans+=(a[n]-a[1]).mod();
    printf("%.2f
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/oier/p/7376323.html