关于计算几何凸包的五种求法(陆续更新)

凸包,在二维平面中可以定义为,一个将所有给出点包含的凸多边形。如下图所示:

绿色线条就是凸包

而在计算几何中凸包有五种求法:

1.穷举法(暴力求解):O(n^{3})

将所有点两两对应,然后将剩下的(n - 2)个点 一一枚举判断是否在同一侧,如果都在同一侧即这两个点是凸包上的点。

具体的算法实现利用到了叉乘。

\begin{pmatrix} &x1 &y1 &1\\ &x2 &y2 &1\\ &x3 &y3 &1 \end{pmatrix}=x1\times y2+x2\times y3+x3\times y1-x3\times y2-x2\times y1-x1\times y3

如果该式子值大于0,即该点在直线左侧,反之着在直线右侧。

空间复杂度:O(N)

时间复杂度:\frac{n(n-1)(n-2)}{2}=O(n^{3})

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
typedef long long ll;
typedef unsigned long long ull;
struct Point{
    double x,y;
    bool ok;
}a[N];
int n;
stack<Point> s;
queue<Point> q;
int cross_product(Point a,Point b,Point c)
{
    if(a.x * b.y + a.y * c.x + b.x * c.y - c.x * b.y - b.x * a.y - a.x * c.y > 0) return 1;
    else if(a.x * b.y + a.y * c.x + b.x * c.y - c.x * b.y - b.x * a.y - a.x * c.y == 0) return 0;
    return -1;
}
void convex_hull()
{
    for(int i = 0;i < n;++i)
        for(int j = i + 1;j < n;++j){
            bool flag = true;
            int left = 0,right = 0;
            for(int k = 0;k < n;++k){
                if(k == i || k == j) ;
                else{
                    if(cross_product(a[i],a[j],a[k]) == 1) left++;
                    else if(cross_product(a[i],a[j],a[k]) == -1) right++;
                    if(left && right)    {flag = false;break;}
                }
            }
            if(flag)    a[i].ok = a[j].ok = true;
        }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for(int i = 0;i < n;++i){
        cin >> a[i].x >> a[i].y;
        a[i].ok = false;
    }
    convex_hull();
    for(int i = 0;i < n;++i)
        if(a[i].ok) cout << a[i].x << ' ' << a[i].y << endl;
    return 0;
}

2,Graham扫描法(常用方法):

先将所有的点按照纵坐标优先的方式排序,显然纵坐标最小的点会在凸包上,所以从纵坐标最小的点开始入栈0,按逆时针方向搜索,将角度最小的点压入栈,然后重复操作。

空间复杂度:O(n)

时间复杂度:O(NM)M为凸包上点的个数

猜你喜欢

转载自blog.csdn.net/qq_41791981/article/details/81214502