• 【题解】「UVA11626」Convex Hull


    凸包模板题。

    之前写过拿 Graham 算法求凸包的,为了不重复/多学点知识,那这次拿 Andrew 算法求凸包吧qaq

    *此文章所有图片均为作者手画。


    Andrew 算法

    假设我们有这些点:

    1.PNG

    首先把所有点以横坐标为第一关键字,纵坐标为第二关键字排序。

    2.PNG

    相对于 Graham 算法来说,Andrew 算法排序更简单,按 (x, y) 坐标排序,时间复杂度也更低(一般的坐标系中排序方法)。

    首先将 (p_1) 入栈。

    然后也将 (p_2) 入栈,(p_2) 可能在,也可能不在,等着之后判断。

    3.PNG

    随后,发现 (p_3) 偏右,所以我们将 (p_2) 出栈。

    4.PNG

    发现 (p_4) 依然偏右,(p_3) 出栈,(p_4) 入栈。

    5.PNG

    (p_5) 向右,(p_4) 出栈,(p_5) 入栈。

    6.PNG

    (p_6) 向左,入栈。

    7.PNG

    (p_7) 向右,(p_6) 出栈,(p_7) 入栈。

    8.PNG

    (p_8) 向右,(p_7) 出栈,继续检查发现相对于 (p_5) (p_8) 仍然向右,(p_5) 出栈,(p_8) 入栈。

    9.PNG

    此时,我们发现,凸包明明还空一半就到头了???

    然而这是意料之中,我们这种算法必然会只算出一半的凸包。

    所以我们需要再从排序末尾的点(也就是 (p_8))出发,按照一模一样的方式再算一遍就行了。

    当然如果我们走过的点就不许要再走了(除了 (p_1)

    (p_8)(p_7),向左,(p_7) 入栈。

    10.PNG

    (p_6) 向右,(p_7) 出栈,(p_6) 入栈。

    11.PNG

    (p_5) 向左,入栈。

    12.PNG

    (p_4) 向左,入栈。

    13.PNG

    (p_3) 向右,(p_4) 出栈,对于 (p_5) (p_3) 依然向右,(p_5) 出栈,(p_3) 入栈。

    14.PNG

    (p_2) 向右,(p_3) 出栈,(p_2) 入栈。

    15.PNG

    最后将 (p_2)(p_1) 连起来。

    16.PNG

    至此,我们的 Andrew 算法就完成了!

    扫描的时间复杂度:(O(n))(已过滤常数)

    排序时间复杂度:(O(n log n))

    总时间复杂度:(O(n log n))


    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #define line cout << endl
    using namespace std;
    const int NR = 1e5 + 5;
    const double eps = 1e-7;
    int n;
    struct point {
        double x, y;
        point () {}
        point (double a, double b) : x (a), y (b) {}
        bool operator < (const point &b) const {
            if (x < b.x) return 1;
            if (x > b.x) return 0;
            return y < b.y;
        }
        point operator - (const point &b) {
            return point (x - b.x, y - b.y);
        }
    };
    point p[NR], sp[NR];
    int cmp (double x) {
        if (fabs (x) < eps) return 0;
        return x > 0 ? 1 : -1;
    }
    double dis (point a, point b) {
        return sqrt ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    double cp (point a, point b) {
        return a.x * b.y - a.y * b.x;
    }
    int Andrew () {
        sort (p + 1, p + 1 + n);
        int len = 0;
        for (int i = 1; i <= n; i++) {
            while (len > 1 && cmp (cp (sp[len] - sp[len - 1], p[i] - sp[len - 1])) < 0) 
                len--;
            sp[++len] = p[i];
        }
        int k = len;
        for (int i = n - 1; i >= 1; i--) {
            while (len > k && cmp (cp (sp[len] - sp[len - 1], p[i] - sp[len - 1])) < 0)
                len--;
            sp[++len] = p[i];
        }
        return len;
    }
    int main () {
        int t;
        cin >> t;
        while (t--) {
            cin >> n;
            char c;
            for (int i = 1; i <= n; i++)
                cin >> p[i].x >> p[i].y >> c;
            int t = Andrew();
            cout << t - 1 << endl;
            for (int i = 1; i < t; i++) 
                printf ("%.0lf %.0lf
    ", sp[i].x, sp[i].y);
        }
        return 0;
    }
    

    谢谢qaq

  • 相关阅读:
    py基础之模块与包
    py装饰器,生成器,迭代器
    py函数式编程
    py基础之列表生成式
    算法基础之递归算法
    Py基础之函数
    py基础之无序列表
    py基础之数据类型及基本语法
    jsp报错问题汇总
    mysql问题汇总
  • 原文地址:https://www.cnblogs.com/-TNT-/p/solution-uva11626.html
Copyright © 2020-2023  润新知