「二维凸包」学习笔记

何为凸包

凸包也就是类似求这样一个东西:

给出一个点集,先在需要找出能围住所有点的一个周长最小的最小凸多边形。也就相当于选出位于最外层的点,将他们连接起来。

注意凸包是不可能凹的,因为存在一个凹口时,可以连接两边的点,反而让周长更小了

凸包的求解

求解凸包一般使用\(Andrew\)算法

此算法的大致过程如下:

将所有点按\(x\)坐标从小到大排序,并以\(y\)为第二关键字从小到大排序。然后先做下凸包,上凸包类似

下凸包的做法是:先将前两个点入栈,然后扫描,每次碰到当前点位于向量\((top-1,top)\)下方时就\(pop\),直到可以保证凸(不凹)为止

如何判断一个点在一个向量下方?用叉积即可。由于叉积是乘\(sin\)的,所以叉积的正负就取决于角度的正负

时间复杂度:\(O(nlogn+2n)\)

代码如下

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
#define  r  read()
using namespace std;
typedef long long ll;
const int MAXN = 10010;
const int MAXM = 20010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N;
struct Coordinate{
    double x, y;
};
Coordinate a[MAXN];
double ans;
int top,sta[MAXN];
inline bool cmp(const Coordinate& a, const Coordinate& b){
    if(a.x != b.x) return a.x < b.x;
    return a.y < b.y;
}
inline double sqr(const double _X){
    return _X * _X;
}
inline double dist(int _a, int _b){
    double x1 = a[_a].x, y1 = a[_a].y;
    double x2 = a[_b].x, y2 = a[_b].y;
    return sqrt(sqr(x1-x2)+sqr(y1-y2));
}
inline double Cross(int _a, int _b, int _c){
    double x1 = a[_b].x-a[_a].x, y1 = a[_b].y-a[_a].y;
    double x2 = a[_c].x-a[_a].x, y2 = a[_c].y-a[_a].y;
    return x1*y2 - x2*y1;
}
inline void ConvexHull(){
    sort(a+1, a+N+1, cmp);
    top = 2;
    sta[1] = 1, sta[2] = 2;
    ans = dist(sta[1], sta[2]);
    for(int i = 3; i <= N; ++i){
        while(top > 1 && Cross(sta[top-1],i,sta[top]) > 0){
            ans -= dist(sta[top-1], sta[top]);
            --top;
        }
        ans += dist(sta[top],i);
        sta[++top] = i;
    }
    top = 2;
    sta[1] = N, sta[2] = N-1;
    ans += dist(sta[1], sta[2]);
    for(int i = N-2; i > 0; --i){
        while(top > 1 && Cross(sta[top-1],i,sta[top]) > 0){
            ans -= dist(sta[top-1], sta[top]);
            --top;
        }
        ans += dist(sta[top],i);
        sta[++top] = i;
    }
}
int main(){
    scanf("%d", &N);
    for(int i = 1; i <= N; ++i){
        scanf("%lf %lf", &a[i].x, &a[i].y);
    }
    ConvexHull();
    printf("%.2f", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qixingzhi/p/9565712.html