MENU

凸包问题

首先介绍下什么是凸包?如下图:

在一个二维坐标系中,有若干点杂乱排列着,将最外层的点连接起来构成的凸多边型,它能包含给定的所有的点,这个多边形就是凸包。

寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在$O(nlogn)$的时间内找到凸包。

Graham Scan算法的做法是先确定一个起点(一般是最左边的点和最右边的点),然后一个个点扫过去,如果新加入的点和之前已经找到的点所构成的"壳"凸性没有变化,就继续扫,否则就把已经找到的最后一个点删去,再比较凸性,直到凸性不发生变化。分别扫描上下两个"壳",合并在一起,凸包就找到了。这么说很抽象,我们看图来解释:

先找"下壳",上下其实是一样的。首先加入两个点A和B。

然后插入第三个点C,并计算$\overrightarrow{AB}×\overrightarrow{BC}$的向量积,却发现向量积系数小于(等于)0,也就是说$\overrightarrow{BC}$在$\overrightarrow{AB}$的顺时针方向上。

于是删去B点。

按照这样的方法依次扫描,找完"下壳"后,再找"上壳"。

关于扫描的顺序,有坐标序和极角序两种,本文采用前者。坐标序是比较两个点的x坐标,如果小的先被扫描(扫描上凸壳的时候反过来);如果两个点x坐标相同,那么就比较y坐标,小的先被扫描(扫描上凸壳的时候也是反过来)。极角序使用atan2函数的返回值进行比较,读者可以自己尝试写下。

下面贴下代码:

struct Point
{
    double x, y;

    Point operator-(Point & p)
    {
        Point t;
        t.x = x - p.x;
        t.y = y - p.y;
        return t;
    }

    double cross(Point p) // 向量叉积
    {
        return x * p.y - p.x * y;
    }
};

bool cmp(Point & p1, Point & p2)
{
    if (p1.x != p2.x)
        return p1.x < p2.x;

    return p1.y < p2.y;
}

Point point[1005];  // 无序点
int   convex[1005]; // 保存组成凸包的点的下标
int   n;            // 坐标系的无序点的个数

int GetConvexHull()
{
    sort(point, point + n, cmp);
    int temp;
    int total = 0;

    for (int i = 0; i < n; i++) // 下凸包
    {
        while (total > 1 && 
               (point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)
            total--;

        convex[total++] = i;
    }

    temp = total;

    for (int i = n - 2; i >= 0; i--) // 上凸包
    {
        while (total > temp && 
               (point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)
            total--;

        convex[total++] = i;
    }

    return total - 1; // 返回组成凸包的点的个数,实际上多了一个,就是起点,所以组成凸包的点个数是 total - 1
}

参考文献:

返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码
添加新评论

6 条评论
  1. epoch epoch

    碰巧你和我本科室友同名同姓。。。我就想问问这个网站用了什么框架么?好好看

  2. 吱吱 吱吱

    #(期待)

  3. 顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶

  4. Immanito Immanito

    用的哪里的主机啊。。。。我之前的主机装不了这个博客

    1. @Immanito衡天的

  5. 您的文章很好, 学习一下@(太开心)